random click and gesture for android 7.0+!!!
This commit is contained in:
@@ -0,0 +1,175 @@
|
||||
package com.stardust.automator;
|
||||
|
||||
import android.accessibilityservice.AccessibilityService;
|
||||
import android.accessibilityservice.GestureDescription;
|
||||
import android.content.Context;
|
||||
import android.graphics.Path;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.support.annotation.RequiresApi;
|
||||
import android.view.ViewConfiguration;
|
||||
|
||||
import com.stardust.concurrent.VolatileBox;
|
||||
import com.stardust.util.ScreenMetrics;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/5/16.
|
||||
*/
|
||||
|
||||
public class GlobalActionAutomator {
|
||||
|
||||
private AccessibilityService mService;
|
||||
private ScreenMetrics mScreenMetrics;
|
||||
|
||||
public void setService(AccessibilityService service) {
|
||||
mService = service;
|
||||
}
|
||||
|
||||
public void setScreenMetrics(ScreenMetrics screenMetrics) {
|
||||
mScreenMetrics = screenMetrics;
|
||||
}
|
||||
|
||||
public boolean back() {
|
||||
return performGlobalAction(AccessibilityService.GLOBAL_ACTION_BACK);
|
||||
}
|
||||
|
||||
public boolean home() {
|
||||
return performGlobalAction(AccessibilityService.GLOBAL_ACTION_HOME);
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
||||
public boolean powerDialog() {
|
||||
return performGlobalAction(AccessibilityService.GLOBAL_ACTION_POWER_DIALOG);
|
||||
}
|
||||
|
||||
private boolean performGlobalAction(int globalAction) {
|
||||
if (mService == null)
|
||||
return false;
|
||||
return mService.performGlobalAction(globalAction);
|
||||
}
|
||||
|
||||
public boolean notifications() {
|
||||
return performGlobalAction(AccessibilityService.GLOBAL_ACTION_NOTIFICATIONS);
|
||||
}
|
||||
|
||||
public boolean quickSettings() {
|
||||
return performGlobalAction(AccessibilityService.GLOBAL_ACTION_QUICK_SETTINGS);
|
||||
}
|
||||
|
||||
public boolean recents() {
|
||||
return performGlobalAction(AccessibilityService.GLOBAL_ACTION_RECENTS);
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.N)
|
||||
public boolean splitScreen() {
|
||||
return performGlobalAction(AccessibilityService.GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN);
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.N)
|
||||
public boolean gesture(long start, long duration, int[]... points) {
|
||||
Path path = pointsToPath(points);
|
||||
return gestures(new GestureDescription.StrokeDescription(path, start, duration));
|
||||
}
|
||||
|
||||
private Path pointsToPath(int[][] points) {
|
||||
Path path = new Path();
|
||||
path.moveTo(scaleX(points[0][0]), scaleY(points[0][1]));
|
||||
for (int i = 1; i < points.length; i++) {
|
||||
int[] point = points[i];
|
||||
path.lineTo(scaleX(point[0]), scaleY(point[1]));
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.N)
|
||||
public void gestureAsync(long start, long duration, int[]... points) {
|
||||
Path path = pointsToPath(points);
|
||||
gesturesAsync(new GestureDescription.StrokeDescription(path, start, duration));
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.N)
|
||||
public boolean gestures(GestureDescription.StrokeDescription... strokes) {
|
||||
if (mService == null)
|
||||
return false;
|
||||
GestureDescription.Builder builder = new GestureDescription.Builder();
|
||||
for (GestureDescription.StrokeDescription stroke : strokes) {
|
||||
builder.addStroke(stroke);
|
||||
}
|
||||
prepareLooperIfNeeded();
|
||||
final VolatileBox<Boolean> result = new VolatileBox<>(false);
|
||||
Handler handler = new Handler(Looper.myLooper());
|
||||
mService.dispatchGesture(builder.build(), new AccessibilityService.GestureResultCallback() {
|
||||
@Override
|
||||
public void onCompleted(GestureDescription gestureDescription) {
|
||||
result.set(true);
|
||||
quitLoop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancelled(GestureDescription gestureDescription) {
|
||||
result.set(false);
|
||||
quitLoop();
|
||||
}
|
||||
}, handler);
|
||||
Looper.loop();
|
||||
return result.get();
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.N)
|
||||
public void gesturesAsync(GestureDescription.StrokeDescription... strokes) {
|
||||
if (mService == null)
|
||||
return;
|
||||
GestureDescription.Builder builder = new GestureDescription.Builder();
|
||||
for (GestureDescription.StrokeDescription stroke : strokes) {
|
||||
builder.addStroke(stroke);
|
||||
}
|
||||
mService.dispatchGesture(builder.build(), null, null);
|
||||
}
|
||||
|
||||
private void quitLoop() {
|
||||
Looper looper = Looper.myLooper();
|
||||
if (looper != null) {
|
||||
looper.quitSafely();
|
||||
}
|
||||
}
|
||||
|
||||
private void prepareLooperIfNeeded() {
|
||||
if (Looper.myLooper() == null) {
|
||||
Looper.prepare();
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.N)
|
||||
public boolean click(int x, int y) {
|
||||
return press(x, y, ViewConfiguration.getTapTimeout() + 50);
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.N)
|
||||
public boolean press(int x, int y, int delay) {
|
||||
return gesture(0, delay, new int[]{x, y});
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.N)
|
||||
public boolean longClick(int x, int y) {
|
||||
return gesture(0, ViewConfiguration.getLongPressTimeout() + 200, new int[]{x, y});
|
||||
}
|
||||
|
||||
private int scaleX(int x) {
|
||||
if (mScreenMetrics == null)
|
||||
return x;
|
||||
return mScreenMetrics.scaleX(x);
|
||||
}
|
||||
|
||||
private int scaleY(int y) {
|
||||
if (mScreenMetrics == null)
|
||||
return y;
|
||||
return mScreenMetrics.scaleY(y);
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.N)
|
||||
public boolean swipe(int x1, int y1, int x2, int y2, int delay) {
|
||||
return gesture(0, delay, new int[]{x1, y1}, new int[]{x2, y2});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,6 +14,8 @@ import java.util.Set;
|
||||
|
||||
public interface AccessibilityDelegate {
|
||||
|
||||
Set<Integer> ALL_EVENT_TYPES = null;
|
||||
|
||||
boolean onAccessibilityEvent(AccessibilityService service, AccessibilityEvent event);
|
||||
|
||||
/**
|
||||
|
||||
@@ -30,41 +30,40 @@ public class AccessibilityInfoProvider implements AccessibilityDelegate {
|
||||
mPackageManager = packageManager;
|
||||
}
|
||||
|
||||
public synchronized String getLatestPackage() {
|
||||
public String getLatestPackage() {
|
||||
return mLatestPackage;
|
||||
}
|
||||
|
||||
public synchronized String getLatestActivity() {
|
||||
public String getLatestActivity() {
|
||||
return mLatestActivity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onAccessibilityEvent(AccessibilityService service, AccessibilityEvent event) {
|
||||
AccessibilityNodeInfo root = service.getRootInActiveWindow();
|
||||
if (root != null)
|
||||
setLatestComponent(root.getPackageName(), event.getClassName());
|
||||
else
|
||||
if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
|
||||
setLatestComponent(event.getPackageName(), event.getClassName());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Integer> getEventTypes() {
|
||||
return null;
|
||||
return ALL_EVENT_TYPES;
|
||||
}
|
||||
|
||||
private synchronized void setLatestComponent(CharSequence latestPackage, CharSequence latestClass) {
|
||||
if (latestPackage == null)
|
||||
private void setLatestComponent(CharSequence latestPackage, CharSequence latestClass) {
|
||||
if (latestPackage == null || latestClass == null)
|
||||
return;
|
||||
mLatestPackage = latestPackage.toString();
|
||||
if (latestClass == null)
|
||||
String latestPackageStr = latestPackage.toString();
|
||||
String latestClassStr = latestClass.toString();
|
||||
if (latestClassStr.startsWith("android.view.") || latestClassStr.startsWith("android.widget."))
|
||||
return;
|
||||
try {
|
||||
ComponentName componentName = new ComponentName(latestPackage.toString(), latestClass.toString());
|
||||
ActivityInfo activityInfo = mPackageManager.getActivityInfo(componentName, 0);
|
||||
mLatestActivity = activityInfo.name;
|
||||
ComponentName componentName = new ComponentName(latestPackageStr, latestClassStr);
|
||||
mLatestActivity = mPackageManager.getActivityInfo(componentName, 0).name;
|
||||
} catch (PackageManager.NameNotFoundException ignored) {
|
||||
|
||||
return;
|
||||
}
|
||||
mLatestPackage = latestPackage.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,13 +2,23 @@ package com.stardust.view.accessibility;
|
||||
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/5/2.
|
||||
*/
|
||||
|
||||
public abstract class AccessibilityService extends android.accessibilityservice.AccessibilityService {
|
||||
|
||||
public interface NotificationCallback {
|
||||
void onNotification();
|
||||
}
|
||||
|
||||
private CopyOnWriteArrayList<NotificationCallback> mNotificationCallbacks = new CopyOnWriteArrayList<>();
|
||||
|
||||
@Override
|
||||
|
||||
public AccessibilityNodeInfo getRootInActiveWindow() {
|
||||
try {
|
||||
return super.getRootInActiveWindow();
|
||||
@@ -16,4 +26,5 @@ public abstract class AccessibilityService extends android.accessibilityservice.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user