Skip to content

Commit

Permalink
add toast activity, update code of injectInputEvent
Browse files Browse the repository at this point in the history
  • Loading branch information
codeskyblue committed Dec 24, 2019
1 parent fde549c commit bf3dcd2
Show file tree
Hide file tree
Showing 6 changed files with 294 additions and 77 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

package com.github.uiautomator.stub;

import android.app.Instrumentation;
import android.app.UiAutomation;
import android.content.ClipData;
import android.content.ClipboardManager;
Expand Down Expand Up @@ -75,18 +76,23 @@ public class AutomatorServiceImpl implements AutomatorService {

private UiDevice device;
private UiAutomation uiAutomation;
private Instrumentation mInstrumentation;
private TouchController touchController;
ClipboardManager clipboard;

public AutomatorServiceImpl() {
this.uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
this.device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
mInstrumentation = InstrumentationRegistry.getInstrumentation();
uiAutomation = mInstrumentation.getUiAutomation();
device = UiDevice.getInstance(mInstrumentation);
touchController = new TouchController(mInstrumentation);

handler.post(new Runnable() {
@Override
public void run() {
AutomatorServiceImpl.this.clipboard = (ClipboardManager) InstrumentationRegistry.getTargetContext().getSystemService(Context.CLIPBOARD_SERVICE);
}
});
// play music when loaded
// play music when loaded
soundPool.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener() {
@Override
public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
Expand Down Expand Up @@ -232,13 +238,16 @@ public boolean swipePoints(int[] segments, int segmentSteps) {
// Multi touch is a little complicated
@Override
public boolean injectInputEvent(int action, float x, float y, int metaState) {
MotionEvent e = MotionEvent.obtain(SystemClock.uptimeMillis(),
SystemClock.uptimeMillis(),
action, x, y, metaState);
e.setSource(InputDevice.SOURCE_TOUCHSCREEN);
boolean b = uiAutomation.injectInputEvent(e, true);
e.recycle();
return b;
switch (action) {
case MotionEvent.ACTION_DOWN: // 0
return touchController.touchDown(x, y);
case MotionEvent.ACTION_MOVE: // 2
return touchController.touchMove(x, y);
case MotionEvent.ACTION_UP: // 1
return touchController.touchUp(x, y);
default:
return false;
}
}

/**
Expand Down Expand Up @@ -272,7 +281,7 @@ public String dumpWindowHierarchy(boolean compressed) {
return os.toString("UTF-8");
} catch (IOException e) {
Log.d("dump Window Hierarchy got IOException " + e);
}finally {
} finally {
if (os != null) {
try {
os.close();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
package com.github.uiautomator.stub;

import android.app.Instrumentation;
import android.app.Service;
import android.app.UiAutomation;
import android.content.Context;
import android.os.PowerManager;
import android.os.SystemClock;
import android.support.test.uiautomator.Configurator;
import android.support.test.uiautomator.UiDevice;
import android.util.Log;
import android.view.InputDevice;
import android.view.InputEvent;
import android.view.KeyCharacterMap;
import android.view.MotionEvent;

public class TouchController {
private static final String LOG_TAG = TouchController.class.getSimpleName();
private static final boolean DEBUG = Log.isLoggable(LOG_TAG, Log.DEBUG);
private static final int MOTION_EVENT_INJECTION_DELAY_MILLIS = 5;

private final KeyCharacterMap mKeyCharacterMap =
KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);

private long mDownTime;
private final Instrumentation mInstrumentation;

public TouchController(Instrumentation instrumentation) {
mInstrumentation = instrumentation;
}

public boolean isScreenOn() {
PowerManager pm = (PowerManager) getContext().getSystemService(Service.POWER_SERVICE);
return pm.isScreenOn();
}

private boolean injectEventSync(InputEvent event) {
return getUiAutomation().injectInputEvent(event, true);
}

public boolean touchDown(float x, float y) {
if (DEBUG) {
android.util.Log.d(LOG_TAG, "touchDown (" + x + ", " + y + ")");
}
mDownTime = SystemClock.uptimeMillis();
MotionEvent event = getMotionEvent(mDownTime, mDownTime, MotionEvent.ACTION_DOWN, x, y);
return injectEventSync(event);
}

public boolean touchUp(float x, float y) {
if (DEBUG) {
android.util.Log.d(LOG_TAG, "touchUp (" + x + ", " + y + ")");
}
final long eventTime = SystemClock.uptimeMillis();
MotionEvent event = getMotionEvent(mDownTime, eventTime, MotionEvent.ACTION_UP, x, y);
mDownTime = 0;
return injectEventSync(event);
}

public boolean touchMove(float x, float y) {
if (DEBUG) {
Log.d(LOG_TAG, "touchMove (" + x + ", " + y + ")");
}
final long eventTime = SystemClock.uptimeMillis();
MotionEvent event = getMotionEvent(mDownTime, eventTime, MotionEvent.ACTION_MOVE, x, y);
return injectEventSync(event);
}

private static MotionEvent getMotionEvent(long downTime, long eventTime, int action,
float x, float y) {

MotionEvent.PointerProperties properties = new MotionEvent.PointerProperties();
properties.id = 0;
properties.toolType = Configurator.getInstance().getToolType();

MotionEvent.PointerCoords coords = new MotionEvent.PointerCoords();
coords.pressure = 1;
coords.size = 1;
coords.x = x;
coords.y = y;

return MotionEvent.obtain(downTime, eventTime, action, 1,
new MotionEvent.PointerProperties[]{properties}, new MotionEvent.PointerCoords[]{coords},
0, 0, 1.0f, 1.0f, 0, 0, InputDevice.SOURCE_TOUCHSCREEN, 0);
}

public boolean performMultiPointerGesture(MotionEvent.PointerCoords[]... touches) {
boolean ret = true;
if (touches.length < 2) {
throw new IllegalArgumentException("Must provide coordinates for at least 2 pointers");
}

// Get the pointer with the max steps to inject.
int maxSteps = 0;
for (int x = 0; x < touches.length; x++)
maxSteps = (maxSteps < touches[x].length) ? touches[x].length : maxSteps;

// specify the properties for each pointer as finger touch
MotionEvent.PointerProperties[] properties = new MotionEvent.PointerProperties[touches.length];
MotionEvent.PointerCoords[] pointerCoords = new MotionEvent.PointerCoords[touches.length];
for (int x = 0; x < touches.length; x++) {
MotionEvent.PointerProperties prop = new MotionEvent.PointerProperties();
prop.id = x;
prop.toolType = Configurator.getInstance().getToolType();
properties[x] = prop;

// for each pointer set the first coordinates for touch down
pointerCoords[x] = touches[x][0];
}

// Touch down all pointers
long downTime = SystemClock.uptimeMillis();
MotionEvent event;
event = MotionEvent.obtain(downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, 1,
properties, pointerCoords, 0, 0, 1, 1, 0, 0, InputDevice.SOURCE_TOUCHSCREEN, 0);
ret &= injectEventSync(event);

for (int x = 1; x < touches.length; x++) {
event = MotionEvent.obtain(downTime, SystemClock.uptimeMillis(),
getPointerAction(MotionEvent.ACTION_POINTER_DOWN, x), x + 1, properties,
pointerCoords, 0, 0, 1, 1, 0, 0, InputDevice.SOURCE_TOUCHSCREEN, 0);
ret &= injectEventSync(event);
}

// Move all pointers
for (int i = 1; i < maxSteps - 1; i++) {
// for each pointer
for (int x = 0; x < touches.length; x++) {
// check if it has coordinates to move
if (touches[x].length > i)
pointerCoords[x] = touches[x][i];
else
pointerCoords[x] = touches[x][touches[x].length - 1];
}

event = MotionEvent.obtain(downTime, SystemClock.uptimeMillis(),
MotionEvent.ACTION_MOVE, touches.length, properties, pointerCoords, 0, 0, 1, 1,
0, 0, InputDevice.SOURCE_TOUCHSCREEN, 0);

ret &= injectEventSync(event);
SystemClock.sleep(MOTION_EVENT_INJECTION_DELAY_MILLIS);
}

// For each pointer get the last coordinates
for (int x = 0; x < touches.length; x++)
pointerCoords[x] = touches[x][touches[x].length - 1];

// touch up
for (int x = 1; x < touches.length; x++) {
event = MotionEvent.obtain(downTime, SystemClock.uptimeMillis(),
getPointerAction(MotionEvent.ACTION_POINTER_UP, x), x + 1, properties,
pointerCoords, 0, 0, 1, 1, 0, 0, InputDevice.SOURCE_TOUCHSCREEN, 0);
ret &= injectEventSync(event);
}

Log.i(LOG_TAG, "x " + pointerCoords[0].x);
// first to touch down is last up
event = MotionEvent.obtain(downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, 1,
properties, pointerCoords, 0, 0, 1, 1, 0, 0, InputDevice.SOURCE_TOUCHSCREEN, 0);
ret &= injectEventSync(event);
return ret;
}

private int getPointerAction(int motionEnvent, int index) {
return motionEnvent + (index << MotionEvent.ACTION_POINTER_INDEX_SHIFT);
}

UiAutomation getUiAutomation() {
return getInstrumentation().getUiAutomation();
}

Context getContext() {
return getInstrumentation().getContext();
}

Instrumentation getInstrumentation() {
return mInstrumentation;
}
}
95 changes: 54 additions & 41 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,54 +24,13 @@
xmlns:tools="http://schemas.android.com/tools"
package="com.github.uiautomator">

<uses-permission
android:name="android.permission.ACCESS_MOCK_LOCATION"
tools:ignore="MockLocation,ProtectedPermissions" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

<application
android:allowBackup="true"
android:icon="@drawable/ic_notification"
android:label="@string/app_name"
android:persistent="true"
android:theme="@style/AppTheme"
android:usesCleartextTraffic="true">
<receiver
android:name=".AdbBroadcastReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="send.mock" />
<action android:name="stop.mock" />

</intent-filter>
</receiver>
<service
android:name=".Service"
android:enabled="true"
android:exported="true">
<intent-filter android:priority="10000">
<action android:name="com.github.uiautomator.ACTION_START" />
<action android:name="com.github.uiautomator.ACTION_STOP" />
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</service>

<activity
android:name=".IdentifyActivity"
android:excludeFromRecents="true"
Expand All @@ -95,6 +54,41 @@
</intent-filter>
</activity>

<activity
android:name=".ToastActivity"
android:excludeFromRecents="true"
android:exported="true"
android:noHistory="true"
android:stateNotNeeded="true">
<intent-filter>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>

<receiver
android:name=".AdbBroadcastReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="send.mock" />
<action android:name="stop.mock" />

</intent-filter>
</receiver>

<service
android:name=".Service"
android:enabled="true"
android:exported="true">
<intent-filter android:priority="10000">
<action android:name="com.github.uiautomator.ACTION_START" />
<action android:name="com.github.uiautomator.ACTION_STOP" />
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</service>

<service
android:name=".FastInputIME"
android:exported="true"
Expand All @@ -109,4 +103,23 @@
</service>
</application>

<uses-permission
android:name="android.permission.ACCESS_MOCK_LOCATION"
tools:ignore="MockLocation,ProtectedPermissions" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

</manifest>
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.github.uiautomator;

import android.annotation.TargetApi;
import android.app.Instrumentation;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.media.MediaCodec;
Expand All @@ -9,6 +10,7 @@
import android.media.MediaMuxer;
import android.os.Build;
import android.os.IBinder;
import android.os.Looper;
import android.util.Log;
import android.view.Surface;

Expand Down
Loading

0 comments on commit bf3dcd2

Please sign in to comment.