diff --git a/.idea/caches/build_file_checksums.ser b/.idea/caches/build_file_checksums.ser index 97259e67..bcbe7e87 100644 Binary files a/.idea/caches/build_file_checksums.ser and b/.idea/caches/build_file_checksums.ser differ diff --git a/app/build.gradle b/app/build.gradle index 924a6da6..0613d094 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,5 +1,8 @@ apply plugin: 'com.android.application' -def AAVersion = '4.4.0' +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-android-extensions' + +def AAVersion = '4.5.2' def SupportLibVersion = '28.0.0' configurations.all { diff --git a/app/src/main/java/org/autojs/autojs/autojs/AutoJs.java b/app/src/main/java/org/autojs/autojs/autojs/AutoJs.java index 6e0f0c3f..a58f5615 100644 --- a/app/src/main/java/org/autojs/autojs/autojs/AutoJs.java +++ b/app/src/main/java/org/autojs/autojs/autojs/AutoJs.java @@ -126,7 +126,7 @@ public class AutoJs extends com.stardust.autojs.AutoJs { } public void ensureAccessibilityServiceEnabled() { - if (AccessibilityService.getInstance() != null) { + if (AccessibilityService.Companion.getInstance() != null) { return; } String errorMessage = null; @@ -149,7 +149,7 @@ public class AutoJs extends com.stardust.autojs.AutoJs { @Override public void waitForAccessibilityServiceEnabled() { - if (AccessibilityService.getInstance() != null) { + if (AccessibilityService.Companion.getInstance() != null) { return; } String errorMessage = null; @@ -166,7 +166,7 @@ public class AutoJs extends com.stardust.autojs.AutoJs { } if (errorMessage != null) { AccessibilityServiceTool.goToAccessibilitySetting(); - if (!org.autojs.autojs.accessibility.AccessibilityService.waitForEnabled(-1)) { + if (!org.autojs.autojs.accessibility.AccessibilityService.Companion.waitForEnabled(-1)) { throw new ScriptInterruptedException(); } } diff --git a/app/src/main/java/org/autojs/autojs/autojs/key/GlobalKeyObserver.java b/app/src/main/java/org/autojs/autojs/autojs/key/GlobalKeyObserver.java index 29db0e58..61bf6168 100644 --- a/app/src/main/java/org/autojs/autojs/autojs/key/GlobalKeyObserver.java +++ b/app/src/main/java/org/autojs/autojs/autojs/key/GlobalKeyObserver.java @@ -34,7 +34,7 @@ public class GlobalKeyObserver implements OnKeyListener, ShellKeyObserver.KeyLis private boolean mVolumeUpFromShell, mVolumeUpFromAccessibility; GlobalKeyObserver() { - AccessibilityService.getStickOnKeyObserver() + AccessibilityService.Companion.getStickOnKeyObserver() .addListener(this); ShellKeyObserver observer = new ShellKeyObserver(); observer.setKeyListener(this); diff --git a/app/src/main/java/org/autojs/autojs/external/tile/LayoutInspectTileService.java b/app/src/main/java/org/autojs/autojs/external/tile/LayoutInspectTileService.java index 962931f9..f573622f 100644 --- a/app/src/main/java/org/autojs/autojs/external/tile/LayoutInspectTileService.java +++ b/app/src/main/java/org/autojs/autojs/external/tile/LayoutInspectTileService.java @@ -50,7 +50,7 @@ public abstract class LayoutInspectTileService extends TileService implements La super.onClick(); Log.d(getClass().getName(), "onClick"); sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)); - if (AccessibilityService.getInstance() == null) { + if (AccessibilityService.Companion.getInstance() == null) { Toast.makeText(this, R.string.text_no_accessibility_permission_to_capture, Toast.LENGTH_SHORT).show(); AccessibilityServiceTool.goToAccessibilitySetting(); inactive(); diff --git a/app/src/main/java/org/autojs/autojs/tool/AccessibilityServiceTool.java b/app/src/main/java/org/autojs/autojs/tool/AccessibilityServiceTool.java index fb11cf62..e5570eb4 100644 --- a/app/src/main/java/org/autojs/autojs/tool/AccessibilityServiceTool.java +++ b/app/src/main/java/org/autojs/autojs/tool/AccessibilityServiceTool.java @@ -38,7 +38,7 @@ public class AccessibilityServiceTool { GlobalAppContext.toast(context.getString(R.string.text_please_choose) + context.getString(R.string._app_name)); } try { - AccessibilityServiceUtils.goToAccessibilitySetting(context); + AccessibilityServiceUtils.INSTANCE.goToAccessibilitySetting(context); } catch (ActivityNotFoundException e) { GlobalAppContext.toast(context.getString(R.string.go_to_accessibility_settings) + context.getString(R.string._app_name)); } @@ -66,19 +66,19 @@ public class AccessibilityServiceTool { public static boolean enableAccessibilityServiceByRootAndWaitFor(long timeOut) { if (enableAccessibilityServiceByRoot(sAccessibilityServiceClass)) { - return AccessibilityService.waitForEnabled(timeOut); + return AccessibilityService.Companion.waitForEnabled(timeOut); } return false; } public static void enableAccessibilityServiceByRootIfNeeded() { - if (AccessibilityService.getInstance() == null) + if (AccessibilityService.Companion.getInstance() == null) if (Pref.shouldEnableAccessibilityServiceByRoot()) { AccessibilityServiceTool.enableAccessibilityServiceByRoot(sAccessibilityServiceClass); } } public static boolean isAccessibilityServiceEnabled(Context context) { - return AccessibilityServiceUtils.isAccessibilityServiceEnabled(context, sAccessibilityServiceClass); + return AccessibilityServiceUtils.INSTANCE.isAccessibilityServiceEnabled(context, sAccessibilityServiceClass); } } diff --git a/app/src/main/java/org/autojs/autojs/tool/CrashHandler.java b/app/src/main/java/org/autojs/autojs/tool/CrashHandler.java index 8a958002..f488b7e0 100644 --- a/app/src/main/java/org/autojs/autojs/tool/CrashHandler.java +++ b/app/src/main/java/org/autojs/autojs/tool/CrashHandler.java @@ -47,7 +47,7 @@ public class CrashHandler extends CrashReport.CrashHandleCallback implements Unc } return; } - AccessibilityService service = AccessibilityService.getInstance(); + AccessibilityService service = AccessibilityService.Companion.getInstance(); if (service != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { Log.d(TAG, "disable service: " + service); service.disableSelf(); diff --git a/app/src/main/java/org/autojs/autojs/ui/floating/CircularMenu.java b/app/src/main/java/org/autojs/autojs/ui/floating/CircularMenu.java index 96852a0b..cde99702 100644 --- a/app/src/main/java/org/autojs/autojs/ui/floating/CircularMenu.java +++ b/app/src/main/java/org/autojs/autojs/ui/floating/CircularMenu.java @@ -218,7 +218,7 @@ public class CircularMenu implements Recorder.OnStateChangedListener, LayoutInsp mLayoutInspectDialog.dismiss(); mLayoutInspectDialog = null; } - if (AccessibilityService.getInstance() == null) { + if (AccessibilityService.Companion.getInstance() == null) { Toast.makeText(mContext, R.string.text_no_accessibility_permission_to_capture, Toast.LENGTH_SHORT).show(); AccessibilityServiceTool.goToAccessibilitySetting(); return; diff --git a/app/src/main/java/org/autojs/autojs/ui/floating/layoutinspector/LayoutHierarchyView.java b/app/src/main/java/org/autojs/autojs/ui/floating/layoutinspector/LayoutHierarchyView.java index 24d3523d..385605d6 100644 --- a/app/src/main/java/org/autojs/autojs/ui/floating/layoutinspector/LayoutHierarchyView.java +++ b/app/src/main/java/org/autojs/autojs/ui/floating/layoutinspector/LayoutHierarchyView.java @@ -232,7 +232,7 @@ public class LayoutHierarchyView extends MultiLevelListView { viewHolder = (ViewHolder) convertView.getTag(); } - viewHolder.nameView.setText(simplifyClassName(nodeInfo.className)); + viewHolder.nameView.setText(simplifyClassName(nodeInfo.getClassName())); viewHolder.nodeInfo = nodeInfo; if (viewHolder.infoView.getVisibility() == VISIBLE) viewHolder.infoView.setText(getItemInfoDsc(itemInfo)); diff --git a/app/src/main/java/org/autojs/autojs/ui/main/drawer/DrawerFragment.java b/app/src/main/java/org/autojs/autojs/ui/main/drawer/DrawerFragment.java index a9c6f7fb..c4439965 100644 --- a/app/src/main/java/org/autojs/autojs/ui/main/drawer/DrawerFragment.java +++ b/app/src/main/java/org/autojs/autojs/ui/main/drawer/DrawerFragment.java @@ -206,7 +206,7 @@ public class DrawerFragment extends android.support.v4.app.Fragment { if (checked && !isAccessibilityServiceEnabled) { enableAccessibilityService(); } else if (!checked && isAccessibilityServiceEnabled) { - if (!AccessibilityService.disable()) { + if (!AccessibilityService.Companion.disable()) { AccessibilityServiceTool.goToAccessibilitySetting(); } } @@ -216,7 +216,7 @@ public class DrawerFragment extends android.support.v4.app.Fragment { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP_MR1) { return; } - boolean enabled = NotificationListenerService.getInstance() != null; + boolean enabled = NotificationListenerService.Companion.getInstance() != null; boolean checked = holder.getSwitchCompat().isChecked(); if ((checked && !enabled) || (!checked && enabled)) { startActivity(new Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS)); @@ -390,7 +390,7 @@ public class DrawerFragment extends android.support.v4.app.Fragment { private void syncSwitchState() { setChecked(mAccessibilityServiceItem, AccessibilityServiceTool.isAccessibilityServiceEnabled(getActivity())); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { - setChecked(mNotificationPermissionItem, NotificationListenerService.getInstance() != null); + setChecked(mNotificationPermissionItem, NotificationListenerService.Companion.getInstance() != null); } } diff --git a/autojs/build.gradle b/autojs/build.gradle index e6ccc07f..083d7d54 100644 --- a/autojs/build.gradle +++ b/autojs/build.gradle @@ -1,4 +1,6 @@ apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-android-extensions' android { compileSdkVersion versions.compile diff --git a/autojs/src/main/java/com/stardust/autojs/AutoJs.java b/autojs/src/main/java/com/stardust/autojs/AutoJs.java index 1e056590..21d59c11 100644 --- a/autojs/src/main/java/com/stardust/autojs/AutoJs.java +++ b/autojs/src/main/java/com/stardust/autojs/AutoJs.java @@ -166,9 +166,9 @@ public abstract class AutoJs { private void addAccessibilityServiceDelegates() { - AccessibilityService.addDelegate(100, mAccessibilityInfoProvider); - AccessibilityService.addDelegate(200, mNotificationObserver); - AccessibilityService.addDelegate(300, mAccessibilityActionRecorder); + AccessibilityService.Companion.addDelegate(100, mAccessibilityInfoProvider); + AccessibilityService.Companion.addDelegate(200, mNotificationObserver); + AccessibilityService.Companion.addDelegate(300, mAccessibilityActionRecorder); } public AccessibilityActionRecorder getAccessibilityActionRecorder() { @@ -225,7 +225,7 @@ public abstract class AutoJs { @Nullable @Override public AccessibilityService getService() { - return AccessibilityService.getInstance(); + return AccessibilityService.Companion.getInstance(); } @Override diff --git a/autojs/src/main/java/com/stardust/autojs/codegeneration/ReadOnlyUiObject.java b/autojs/src/main/java/com/stardust/autojs/codegeneration/ReadOnlyUiObject.java index 56aac9e5..d449de40 100644 --- a/autojs/src/main/java/com/stardust/autojs/codegeneration/ReadOnlyUiObject.java +++ b/autojs/src/main/java/com/stardust/autojs/codegeneration/ReadOnlyUiObject.java @@ -17,12 +17,12 @@ public class ReadOnlyUiObject extends UiObject { private NodeInfo mNodeInfo; public ReadOnlyUiObject(NodeInfo info) { - super(null, info.depth, -1); + super(null, info.getDepth(), -1); mNodeInfo = info; } public ReadOnlyUiObject(NodeInfo info, int indexInParent) { - super(null, info.depth, indexInParent); + super(null, info.getDepth(), indexInParent); mNodeInfo = info; } @@ -35,7 +35,7 @@ public class ReadOnlyUiObject extends UiObject { @Nullable @Override public UiObject parent() { - return mNodeInfo.parent == null ? null : new ReadOnlyUiObject(mNodeInfo.parent); + return mNodeInfo.getParent() == null ? null : new ReadOnlyUiObject(mNodeInfo.getParent()); } @Override @@ -50,7 +50,7 @@ public class ReadOnlyUiObject extends UiObject { @Override public String className() { - return mNodeInfo.className; + return mNodeInfo.getClassName(); } @Override @@ -60,7 +60,7 @@ public class ReadOnlyUiObject extends UiObject { @Override public String packageName() { - return mNodeInfo.packageName; + return mNodeInfo.getPackageName(); } @Override @@ -70,12 +70,12 @@ public class ReadOnlyUiObject extends UiObject { @Override public String id() { - return mNodeInfo.id; + return mNodeInfo.getId(); } @Override public String desc() { - return mNodeInfo.desc; + return mNodeInfo.getDesc(); } @Override @@ -101,13 +101,13 @@ public class ReadOnlyUiObject extends UiObject { @Override public int drawingOrder() { - return mNodeInfo.drawingOrder; + return mNodeInfo.getDrawingOrder(); } @NonNull @Override public String text() { - return mNodeInfo.text; + return mNodeInfo.getText(); } @Override @@ -138,62 +138,62 @@ public class ReadOnlyUiObject extends UiObject { @Override public int depth() { - return mNodeInfo.depth; + return mNodeInfo.getDepth(); } @Override public boolean checkable() { - return mNodeInfo.checkable; + return mNodeInfo.getCheckable(); } @Override public boolean checked() { - return mNodeInfo.checked; + return mNodeInfo.getChecked(); } @Override public boolean focusable() { - return mNodeInfo.focusable; + return mNodeInfo.getFocusable(); } @Override public boolean focused() { - return mNodeInfo.focused; + return mNodeInfo.getFocused(); } @Override public boolean visibleToUser() { - return mNodeInfo.visibleToUser; + return mNodeInfo.getVisibleToUser(); } @Override public boolean accessibilityFocused() { - return mNodeInfo.accessibilityFocused; + return mNodeInfo.getAccessibilityFocused(); } @Override public boolean selected() { - return mNodeInfo.selected; + return mNodeInfo.getSelected(); } @Override public boolean clickable() { - return mNodeInfo.clickable; + return mNodeInfo.getClickable(); } @Override public boolean longClickable() { - return mNodeInfo.longClickable; + return mNodeInfo.getLongClickable(); } @Override public boolean enabled() { - return mNodeInfo.enabled; + return mNodeInfo.getEnabled(); } @Override public boolean scrollable() { - return mNodeInfo.scrollable; + return mNodeInfo.getScrollable(); } @Override @@ -259,47 +259,47 @@ public class ReadOnlyUiObject extends UiObject { @Override public boolean isContextClickable() { - return mNodeInfo.contextClickable; + return mNodeInfo.getContextClickable(); } @Override public boolean isDismissable() { - return mNodeInfo.dismissable; + return mNodeInfo.getDismissable(); } @Override public boolean isEditable() { - return mNodeInfo.editable; + return mNodeInfo.getEditable(); } @Override public int row() { - return mNodeInfo.row; + return mNodeInfo.getRow(); } @Override public int column() { - return mNodeInfo.column; + return mNodeInfo.getColumn(); } @Override public int rowSpan() { - return mNodeInfo.rowSpan; + return mNodeInfo.getRowSpan(); } @Override public int columnSpan() { - return mNodeInfo.columnSpan; + return mNodeInfo.getColumnSpan(); } @Override public int rowCount() { - return mNodeInfo.rowCount; + return mNodeInfo.getRowCount(); } @Override public int columnCount() { - return mNodeInfo.columnCount; + return mNodeInfo.getColumnCount(); } @Override diff --git a/autojs/src/main/java/com/stardust/autojs/core/accessibility/SimpleActionAutomator.java b/autojs/src/main/java/com/stardust/autojs/core/accessibility/SimpleActionAutomator.java index 19cb6565..a2b8c7d2 100644 --- a/autojs/src/main/java/com/stardust/autojs/core/accessibility/SimpleActionAutomator.java +++ b/autojs/src/main/java/com/stardust/autojs/core/accessibility/SimpleActionAutomator.java @@ -82,22 +82,22 @@ public class SimpleActionAutomator { @ScriptInterface public boolean scrollBackward(int i) { - return performAction(ActionFactory.createScrollAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD, i)); + return performAction(ActionFactory.INSTANCE.createScrollAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD, i)); } @ScriptInterface public boolean scrollForward(int i) { - return performAction(ActionFactory.createScrollAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD, i)); + return performAction(ActionFactory.INSTANCE.createScrollAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD, i)); } @ScriptInterface public boolean scrollMaxBackward() { - return performAction(ActionFactory.createScrollMaxAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD)); + return performAction(ActionFactory.INSTANCE.createScrollMaxAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD)); } @ScriptInterface public boolean scrollMaxForward() { - return performAction(ActionFactory.createScrollMaxAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD)); + return performAction(ActionFactory.INSTANCE.createScrollMaxAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD)); } @ScriptInterface @@ -121,7 +121,7 @@ public class SimpleActionAutomator { @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) public boolean appendText(ActionTarget target, String text) { ScriptRuntime.requiresApi(Build.VERSION_CODES.LOLLIPOP); - return performAction(target.createAction(UiObject.ACTION_APPEND_TEXT, text)); + return performAction(target.createAction(UiObject.Companion.getACTION_APPEND_TEXT(), text)); } @ScriptInterface @@ -257,7 +257,7 @@ public class SimpleActionAutomator { if (root == null) return false; Log.v(TAG, "performAction: " + simpleAction + " root = " + root); - return simpleAction.perform(UiObject.createRoot(root)); + return simpleAction.perform(UiObject.Companion.createRoot(root)); } private boolean isRunningPackageSelf() { diff --git a/autojs/src/main/java/com/stardust/autojs/core/accessibility/UiSelector.java b/autojs/src/main/java/com/stardust/autojs/core/accessibility/UiSelector.java index 3e215aa0..e6e4ea33 100644 --- a/autojs/src/main/java/com/stardust/autojs/core/accessibility/UiSelector.java +++ b/autojs/src/main/java/com/stardust/autojs/core/accessibility/UiSelector.java @@ -90,13 +90,13 @@ public class UiSelector extends UiGlobalSelector { if (BuildConfig.DEBUG) Log.d(TAG, "find: root = " + root); if (root == null) { - return UiObjectCollection.EMPTY; + return UiObjectCollection.Companion.getEMPTY(); } if (root.getPackageName() != null && mAccessibilityBridge.getConfig().whiteListContains(root.getPackageName().toString())) { Log.d(TAG, "package in white list, return null"); - return UiObjectCollection.EMPTY; + return UiObjectCollection.Companion.getEMPTY(); } - return findOf(UiObject.createRoot(root, mAllocator)); + return findOf(UiObject.Companion.createRoot(root, mAllocator)); } @Override diff --git a/autojs/src/main/java/com/stardust/autojs/core/record/accessibility/AccessibilityActionConverter.java b/autojs/src/main/java/com/stardust/autojs/core/record/accessibility/AccessibilityActionConverter.java index 258e88bb..ff346ba3 100644 --- a/autojs/src/main/java/com/stardust/autojs/core/record/accessibility/AccessibilityActionConverter.java +++ b/autojs/src/main/java/com/stardust/autojs/core/record/accessibility/AccessibilityActionConverter.java @@ -78,7 +78,7 @@ public class AccessibilityActionConverter { AccessibilityNodeInfo source = event.getSource(); if (source == null) return; - String bounds = NodeInfo.boundsToString(AccessibilityNodeInfoHelper.getBoundsInScreen(source)); + String bounds = NodeInfo.Companion.boundsToString(AccessibilityNodeInfoHelper.INSTANCE.getBoundsInScreen(source)); source.recycle(); onAccessibilityEvent(event, bounds, sb); } @@ -122,8 +122,8 @@ public class AccessibilityActionConverter { AccessibilityNodeInfo source = event.getSource(); if (source == null) return; - UiObject uiObject = UiObject.createRoot(service.getRootInActiveWindow()); - List editableList = FilterAction.EditableFilter.findEditable(uiObject); + UiObject uiObject = UiObject.Companion.createRoot(service.getRootInActiveWindow()); + List editableList = FilterAction.EditableFilter.Companion.findEditable(uiObject); int i = findInEditableList(editableList, source); sb.append("while(!input(").append(i).append(", \"").append(source.getText()).append("\"));"); source.recycle(); @@ -132,7 +132,7 @@ public class AccessibilityActionConverter { private static int findInEditableList(List editableList, AccessibilityNodeInfo editable) { int i = 0; for (UiObject nodeInfo : editableList) { - if (AccessibilityNodeInfoHelper.getBoundsInScreen(nodeInfo).equals(AccessibilityNodeInfoHelper.getBoundsInScreen(editable))) { + if (AccessibilityNodeInfoHelper.INSTANCE.getBoundsInScreen(nodeInfo).equals(AccessibilityNodeInfoHelper.INSTANCE.getBoundsInScreen(editable))) { return i; } i++; diff --git a/autojs/src/main/java/com/stardust/autojs/runtime/api/Events.java b/autojs/src/main/java/com/stardust/autojs/runtime/api/Events.java index 4a8027ba..a618f45e 100644 --- a/autojs/src/main/java/com/stardust/autojs/runtime/api/Events.java +++ b/autojs/src/main/java/com/stardust/autojs/runtime/api/Events.java @@ -204,13 +204,13 @@ public class Events extends EventEmitter implements OnKeyListener, TouchObserver mListeningNotification = true; ensureHandler(); mLoopers.waitWhenIdle(true); - if (NotificationListenerService.getInstance() == null) { + if (NotificationListenerService.Companion.getInstance() == null) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) { mContext.startActivity(new Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS)); } throw new ScriptException(mContext.getString(R.string.exception_notification_service_disabled)); } - NotificationListenerService.getInstance().addListener(this); + NotificationListenerService.Companion.getInstance().addListener(this); } public void observeToast() { @@ -250,8 +250,8 @@ public class Events extends EventEmitter implements OnKeyListener, TouchObserver mAccessibilityBridge.getNotificationObserver().removeNotificationListener(this); mAccessibilityBridge.getNotificationObserver().removeToastListener(this); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2 - && NotificationListenerService.getInstance() != null) { - NotificationListenerService.getInstance().removeListener(this); + && NotificationListenerService.Companion.getInstance() != null) { + NotificationListenerService.Companion.getInstance().removeListener(this); } } if (mKeyInterceptor != null) { diff --git a/autojs/src/main/java/com/stardust/autojs/util/FloatingPermission.java b/autojs/src/main/java/com/stardust/autojs/util/FloatingPermission.java index d2626d6f..d09ebd39 100644 --- a/autojs/src/main/java/com/stardust/autojs/util/FloatingPermission.java +++ b/autojs/src/main/java/com/stardust/autojs/util/FloatingPermission.java @@ -11,7 +11,7 @@ import android.support.annotation.RequiresApi; import android.text.TextUtils; import android.widget.Toast; -import com.stardust.R; +import com.stardust.autojs.R; import com.stardust.enhancedfloaty.util.FloatingWindowPermissionUtil; import java.lang.reflect.Method; diff --git a/automator/build.gradle b/automator/build.gradle index 91363f60..1737e4be 100644 --- a/automator/build.gradle +++ b/automator/build.gradle @@ -1,4 +1,6 @@ apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-android-extensions' android { compileSdkVersion versions.compile diff --git a/automator/src/androidTest/java/com/stardust/automator/ExampleInstrumentedTest.java b/automator/src/androidTest/java/com/stardust/automator/ExampleInstrumentedTest.java deleted file mode 100644 index bf26d3b7..00000000 --- a/automator/src/androidTest/java/com/stardust/automator/ExampleInstrumentedTest.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.stardust.automator; - -import android.content.Context; -import android.support.test.InstrumentationRegistry; -import android.support.test.runner.AndroidJUnit4; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import static org.junit.Assert.*; - -/** - * Instrumentation test, which will execute on an Android device. - * - * @see Testing documentation - */ -@RunWith(AndroidJUnit4.class) -public class ExampleInstrumentedTest { - @Test - public void useAppContext() throws Exception { - // Context of the app under test. - Context appContext = InstrumentationRegistry.getTargetContext(); - - assertEquals("com.stardust.automator.test", appContext.getPackageName()); - } -} diff --git a/automator/src/androidTest/java/com/stardust/automator/ExampleInstrumentedTest.kt b/automator/src/androidTest/java/com/stardust/automator/ExampleInstrumentedTest.kt new file mode 100644 index 00000000..eb1fb438 --- /dev/null +++ b/automator/src/androidTest/java/com/stardust/automator/ExampleInstrumentedTest.kt @@ -0,0 +1,27 @@ +package com.stardust.automator + +import android.content.Context +import android.support.test.InstrumentationRegistry +import android.support.test.runner.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumentation test, which will execute on an Android device. + * + * @see [Testing documentation](http://d.android.com/tools/testing) + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + @Throws(Exception::class) + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getTargetContext() + + assertEquals("com.stardust.automator.test", appContext.packageName) + } +} diff --git a/automator/src/androidTest/java/com/stardust/automator/simple_action/DepthFirstSearchTargetActionTest.java b/automator/src/androidTest/java/com/stardust/automator/simple_action/DepthFirstSearchTargetActionTest.java deleted file mode 100644 index fb5ff52f..00000000 --- a/automator/src/androidTest/java/com/stardust/automator/simple_action/DepthFirstSearchTargetActionTest.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.stardust.automator.simple_action; - -import android.view.accessibility.AccessibilityNodeInfo; - -import com.stardust.automator.UiObject; -import com.stardust.automator.test.TestUiObject; - -import org.junit.Test; - -import java.util.ArrayList; -import java.util.List; - -import static org.junit.Assert.*; - -/** - * Created by Stardust on 2017/5/5. - */ -public class DepthFirstSearchTargetActionTest { - - @Test - public void perform() { - DepthFirstSearchTargetAction action = new DepthFirstSearchTargetAction(AccessibilityNodeInfo.ACTION_CLICK, new FilterAction.Filter() { - @Override - public List filter(UiObject root) { - List list = new ArrayList<>(); - for (int i = 0; i < root.getChildCount(); i++) { - list.add(root.child(i)); - } - return list; - } - }); - TestUiObject root = new TestUiObject(5); - action.perform(root); - System.out.println(TestUiObject.max); - assertEquals(1, TestUiObject.count); - } - -} \ No newline at end of file diff --git a/automator/src/androidTest/java/com/stardust/automator/simple_action/DepthFirstSearchTargetActionTest.kt b/automator/src/androidTest/java/com/stardust/automator/simple_action/DepthFirstSearchTargetActionTest.kt new file mode 100644 index 00000000..323e86d6 --- /dev/null +++ b/automator/src/androidTest/java/com/stardust/automator/simple_action/DepthFirstSearchTargetActionTest.kt @@ -0,0 +1,34 @@ +package com.stardust.automator.simple_action + +import android.view.accessibility.AccessibilityNodeInfo + +import com.stardust.automator.UiObject +import com.stardust.automator.test.TestUiObject + +import org.junit.Test + +import java.util.ArrayList + +import org.junit.Assert.* + +/** + * Created by Stardust on 2017/5/5. + */ +class DepthFirstSearchTargetActionTest { + + @Test + fun perform() { + val action = DepthFirstSearchTargetAction(AccessibilityNodeInfo.ACTION_CLICK, FilterAction.Filter { root -> + val list = ArrayList() + for (i in 0 until root.childCount) { + list.add(root.child(i)) + } + list + }) + val root = TestUiObject(5) + action.perform(root) + println(TestUiObject.max) + assertEquals(1, TestUiObject.count.toLong()) + } + +} \ No newline at end of file diff --git a/automator/src/androidTest/java/com/stardust/automator/simple_action/ScrollMaxActionTest.java b/automator/src/androidTest/java/com/stardust/automator/simple_action/ScrollMaxActionTest.java deleted file mode 100644 index a13cdee3..00000000 --- a/automator/src/androidTest/java/com/stardust/automator/simple_action/ScrollMaxActionTest.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.stardust.automator.simple_action; - -import android.view.accessibility.AccessibilityNodeInfo; - -import com.stardust.automator.UiObject; -import com.stardust.automator.test.TestUiObject; - -import org.junit.Test; - -import static org.junit.Assert.*; - -/** - * Created by Stardust on 2017/5/5. - */ -public class ScrollMaxActionTest { - @Test - public void perform() throws Exception { - ScrollMaxAction action = new ScrollMaxAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD); - UiObject root = new TestUiObject(20); - action.perform(root); - System.out.println(TestUiObject.max); - assertEquals(1, TestUiObject.count); - } - -} \ No newline at end of file diff --git a/automator/src/androidTest/java/com/stardust/automator/simple_action/ScrollMaxActionTest.kt b/automator/src/androidTest/java/com/stardust/automator/simple_action/ScrollMaxActionTest.kt new file mode 100644 index 00000000..e4adcc2c --- /dev/null +++ b/automator/src/androidTest/java/com/stardust/automator/simple_action/ScrollMaxActionTest.kt @@ -0,0 +1,26 @@ +package com.stardust.automator.simple_action + +import android.view.accessibility.AccessibilityNodeInfo + +import com.stardust.automator.UiObject +import com.stardust.automator.test.TestUiObject + +import org.junit.Test + +import org.junit.Assert.* + +/** + * Created by Stardust on 2017/5/5. + */ +class ScrollMaxActionTest { + @Test + @Throws(Exception::class) + fun perform() { + val action = ScrollMaxAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD) + val root = TestUiObject(20) + action.perform(root) + println(TestUiObject.max) + assertEquals(1, TestUiObject.count.toLong()) + } + +} \ No newline at end of file diff --git a/automator/src/main/java/com/stardust/automator/ActionArgument.java b/automator/src/main/java/com/stardust/automator/ActionArgument.java deleted file mode 100644 index 25fad5e5..00000000 --- a/automator/src/main/java/com/stardust/automator/ActionArgument.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.stardust.automator; - -import android.os.Bundle; - -/** - * Created by Stardust on 2017/3/9. - */ - -public abstract class ActionArgument { - - protected final String mKey; - - private ActionArgument(String key) { - mKey = key; - } - - public abstract void putIn(Bundle bundle); - - public static class IntActionArgument extends ActionArgument { - - private final int mInt; - - public IntActionArgument(String name, int i) { - super(name); - mInt = i; - } - - @Override - public void putIn(Bundle bundle) { - bundle.putInt(mKey, mInt); - } - } - - public static class CharSequenceActionArgument extends ActionArgument { - - private final CharSequence mCharSequence; - - public CharSequenceActionArgument(String name, CharSequence charSequence) { - super(name); - mCharSequence = charSequence; - } - - @Override - public void putIn(Bundle bundle) { - bundle.putCharSequence(mKey, mCharSequence); - } - } - - public static class FloatActionArgument extends ActionArgument { - private final float mFloat; - - public FloatActionArgument(String name, float value) { - super(name); - mFloat = value; - } - - @Override - public void putIn(Bundle bundle) { - bundle.putFloat(mKey, mFloat); - } - } - -} diff --git a/automator/src/main/java/com/stardust/automator/ActionArgument.kt b/automator/src/main/java/com/stardust/automator/ActionArgument.kt new file mode 100644 index 00000000..160f79c1 --- /dev/null +++ b/automator/src/main/java/com/stardust/automator/ActionArgument.kt @@ -0,0 +1,34 @@ +package com.stardust.automator + +import android.os.Bundle + +/** + * Created by Stardust on 2017/3/9. + */ + +abstract class ActionArgument private constructor(protected val mKey: String) { + + abstract fun putIn(bundle: Bundle) + + class IntActionArgument(name: String, private val mInt: Int) : ActionArgument(name) { + + override fun putIn(bundle: Bundle) { + bundle.putInt(mKey, mInt) + } + } + + class CharSequenceActionArgument(name: String, private val mCharSequence: CharSequence) : ActionArgument(name) { + + override fun putIn(bundle: Bundle) { + bundle.putCharSequence(mKey, mCharSequence) + } + } + + class FloatActionArgument(name: String, private val mFloat: Float) : ActionArgument(name) { + + override fun putIn(bundle: Bundle) { + bundle.putFloat(mKey, mFloat) + } + } + +} diff --git a/automator/src/main/java/com/stardust/automator/GlobalActionAutomator.java b/automator/src/main/java/com/stardust/automator/GlobalActionAutomator.java deleted file mode 100644 index c25a7cde..00000000 --- a/automator/src/main/java/com/stardust/automator/GlobalActionAutomator.java +++ /dev/null @@ -1,207 +0,0 @@ -package com.stardust.automator; - -import android.accessibilityservice.AccessibilityService; -import android.accessibilityservice.GestureDescription; -import android.graphics.Path; -import android.os.Build; -import android.os.Handler; -import android.os.Looper; -import android.support.annotation.Nullable; -import android.support.annotation.RequiresApi; -import android.view.ViewConfiguration; - -import com.stardust.concurrent.VolatileBox; -import com.stardust.concurrent.VolatileDispose; -import com.stardust.util.ScreenMetrics; - -/** - * Created by Stardust on 2017/5/16. - */ - -public class GlobalActionAutomator { - - private AccessibilityService mService; - private ScreenMetrics mScreenMetrics; - private Handler mHandler; - - public GlobalActionAutomator(@Nullable Handler handler) { - mHandler = handler; - } - - 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); - } - if (mHandler == null) { - return gesturesWithoutHandler(builder.build()); - } else { - return gesturesWithHandler(builder.build()); - } - } - - @RequiresApi(api = Build.VERSION_CODES.N) - private boolean gesturesWithHandler(GestureDescription description) { - final VolatileDispose result = new VolatileDispose<>(); - mService.dispatchGesture(description, new AccessibilityService.GestureResultCallback() { - @Override - public void onCompleted(GestureDescription gestureDescription) { - result.setAndNotify(true); - } - - @Override - public void onCancelled(GestureDescription gestureDescription) { - result.setAndNotify(false); - } - }, mHandler); - return result.blockedGet(); - } - - @RequiresApi(api = Build.VERSION_CODES.N) - private boolean gesturesWithoutHandler(GestureDescription description) { - prepareLooperIfNeeded(); - final VolatileBox result = new VolatileBox<>(false); - Handler handler = new Handler(Looper.myLooper()); - mService.dispatchGesture(description, 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.quit(); - } - } - - 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}); - } - -} diff --git a/automator/src/main/java/com/stardust/automator/GlobalActionAutomator.kt b/automator/src/main/java/com/stardust/automator/GlobalActionAutomator.kt new file mode 100644 index 00000000..dd807aff --- /dev/null +++ b/automator/src/main/java/com/stardust/automator/GlobalActionAutomator.kt @@ -0,0 +1,189 @@ +package com.stardust.automator + +import android.accessibilityservice.AccessibilityService +import android.accessibilityservice.GestureDescription +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.concurrent.VolatileDispose +import com.stardust.util.ScreenMetrics + +/** + * Created by Stardust on 2017/5/16. + */ + +class GlobalActionAutomator(private val mHandler: Handler?) { + + private var mService: AccessibilityService? = null + private var mScreenMetrics: ScreenMetrics? = null + + fun setService(service: AccessibilityService) { + mService = service + } + + fun setScreenMetrics(screenMetrics: ScreenMetrics) { + mScreenMetrics = screenMetrics + } + + fun back(): Boolean { + return performGlobalAction(AccessibilityService.GLOBAL_ACTION_BACK) + } + + fun home(): Boolean { + return performGlobalAction(AccessibilityService.GLOBAL_ACTION_HOME) + } + + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + fun powerDialog(): Boolean { + return performGlobalAction(AccessibilityService.GLOBAL_ACTION_POWER_DIALOG) + } + + private fun performGlobalAction(globalAction: Int): Boolean { + return if (mService == null) false else mService!!.performGlobalAction(globalAction) + } + + fun notifications(): Boolean { + return performGlobalAction(AccessibilityService.GLOBAL_ACTION_NOTIFICATIONS) + } + + fun quickSettings(): Boolean { + return performGlobalAction(AccessibilityService.GLOBAL_ACTION_QUICK_SETTINGS) + } + + fun recents(): Boolean { + return performGlobalAction(AccessibilityService.GLOBAL_ACTION_RECENTS) + } + + @RequiresApi(api = Build.VERSION_CODES.N) + fun splitScreen(): Boolean { + return performGlobalAction(AccessibilityService.GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN) + } + + @RequiresApi(api = Build.VERSION_CODES.N) + fun gesture(start: Long, duration: Long, vararg points: IntArray): Boolean { + val path = pointsToPath(points) + return gestures(GestureDescription.StrokeDescription(path, start, duration)) + } + + private fun pointsToPath(points: Array): Path { + val path = Path() + path.moveTo(scaleX(points[0][0]).toFloat(), scaleY(points[0][1]).toFloat()) + for (i in 1 until points.size) { + val point = points[i] + path.lineTo(scaleX(point[0]).toFloat(), scaleY(point[1]).toFloat()) + } + return path + } + + @RequiresApi(api = Build.VERSION_CODES.N) + fun gestureAsync(start: Long, duration: Long, vararg points: IntArray) { + val path = pointsToPath(points) + gesturesAsync(GestureDescription.StrokeDescription(path, start, duration)) + } + + @RequiresApi(api = Build.VERSION_CODES.N) + fun gestures(vararg strokes: GestureDescription.StrokeDescription): Boolean { + if (mService == null) + return false + val builder = GestureDescription.Builder() + for (stroke in strokes) { + builder.addStroke(stroke) + } + return if (mHandler == null) { + gesturesWithoutHandler(builder.build()) + } else { + gesturesWithHandler(builder.build()) + } + } + + @RequiresApi(api = Build.VERSION_CODES.N) + private fun gesturesWithHandler(description: GestureDescription): Boolean { + val result = VolatileDispose() + mService!!.dispatchGesture(description, object : AccessibilityService.GestureResultCallback() { + override fun onCompleted(gestureDescription: GestureDescription) { + result.setAndNotify(true) + } + + override fun onCancelled(gestureDescription: GestureDescription) { + result.setAndNotify(false) + } + }, mHandler) + return result.blockedGet() + } + + @RequiresApi(api = Build.VERSION_CODES.N) + private fun gesturesWithoutHandler(description: GestureDescription): Boolean { + prepareLooperIfNeeded() + val result = VolatileBox(false) + val handler = Handler(Looper.myLooper()) + mService!!.dispatchGesture(description, object : AccessibilityService.GestureResultCallback() { + override fun onCompleted(gestureDescription: GestureDescription) { + result.set(true) + quitLoop() + } + + override fun onCancelled(gestureDescription: GestureDescription) { + result.set(false) + quitLoop() + } + }, handler) + Looper.loop() + return result.get() + } + + @RequiresApi(api = Build.VERSION_CODES.N) + fun gesturesAsync(vararg strokes: GestureDescription.StrokeDescription) { + if (mService == null) + return + val builder = GestureDescription.Builder() + for (stroke in strokes) { + builder.addStroke(stroke) + } + mService!!.dispatchGesture(builder.build(), null, null) + } + + private fun quitLoop() { + val looper = Looper.myLooper() + looper?.quit() + } + + private fun prepareLooperIfNeeded() { + if (Looper.myLooper() == null) { + Looper.prepare() + } + } + + @RequiresApi(api = Build.VERSION_CODES.N) + fun click(x: Int, y: Int): Boolean { + return press(x, y, ViewConfiguration.getTapTimeout() + 50) + } + + @RequiresApi(api = Build.VERSION_CODES.N) + fun press(x: Int, y: Int, delay: Int): Boolean { + return gesture(0, delay.toLong(), intArrayOf(x, y)) + } + + @RequiresApi(api = Build.VERSION_CODES.N) + fun longClick(x: Int, y: Int): Boolean { + return gesture(0, (ViewConfiguration.getLongPressTimeout() + 200).toLong(), intArrayOf(x, y)) + } + + private fun scaleX(x: Int): Int { + return if (mScreenMetrics == null) x else mScreenMetrics!!.scaleX(x) + } + + private fun scaleY(y: Int): Int { + return if (mScreenMetrics == null) y else mScreenMetrics!!.scaleY(y) + } + + @RequiresApi(api = Build.VERSION_CODES.N) + fun swipe(x1: Int, y1: Int, x2: Int, y2: Int, delay: Long): Boolean { + return gesture(0, delay, intArrayOf(x1, y1), intArrayOf(x2, y2)) + } + +} diff --git a/automator/src/main/java/com/stardust/automator/UiGlobalSelector.java b/automator/src/main/java/com/stardust/automator/UiGlobalSelector.java deleted file mode 100644 index 59668277..00000000 --- a/automator/src/main/java/com/stardust/automator/UiGlobalSelector.java +++ /dev/null @@ -1,454 +0,0 @@ -package com.stardust.automator; - -import android.graphics.Rect; -import android.os.Build; -import android.support.annotation.Nullable; - -import com.stardust.automator.filter.BooleanFilter; -import com.stardust.automator.filter.BoundsFilter; -import com.stardust.automator.filter.ClassNameFilter; -import com.stardust.automator.filter.DescFilter; -import com.stardust.automator.filter.DfsFilter; -import com.stardust.automator.filter.IdFilter; -import com.stardust.automator.filter.IntFilter; -import com.stardust.automator.filter.ListFilter; -import com.stardust.automator.filter.PackageNameFilter; -import com.stardust.automator.filter.TextFilter; -import com.stardust.automator.simple_action.Able; -import com.stardust.util.Supplier; - -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; -import java.util.Queue; - -/** - * Created by Stardust on 2017/3/8. - */ - -public class UiGlobalSelector { - - private Queue mFilters = new LinkedList<>(); - - //// 第一类筛选条件 - - public UiGlobalSelector id(String id) { - mFilters.add(IdFilter.equals(id)); - return this; - } - - public UiGlobalSelector idContains(String str) { - mFilters.add(IdFilter.contains(str)); - return this; - } - - public UiGlobalSelector idStartsWith(String prefix) { - mFilters.add(IdFilter.startsWith(prefix)); - return this; - } - - public UiGlobalSelector idEndsWith(String suffix) { - mFilters.add(IdFilter.endsWith(suffix)); - return this; - } - - public UiGlobalSelector idMatches(String regex) { - mFilters.add(IdFilter.matches(regex)); - return this; - } - - public UiGlobalSelector text(String text) { - mFilters.add(TextFilter.equals(text)); - return this; - } - - public UiGlobalSelector textContains(String str) { - mFilters.add(TextFilter.contains(str)); - return this; - } - - public UiGlobalSelector textStartsWith(String prefix) { - mFilters.add(TextFilter.startsWith(prefix)); - return this; - } - - public UiGlobalSelector textEndsWith(String suffix) { - mFilters.add(TextFilter.endsWith(suffix)); - return this; - } - - public UiGlobalSelector textMatches(String regex) { - mFilters.add(TextFilter.matches(regex)); - return this; - } - - public UiGlobalSelector desc(String desc) { - mFilters.add(DescFilter.equals(desc)); - return this; - } - - public UiGlobalSelector descContains(String str) { - mFilters.add(DescFilter.contains(str)); - return this; - } - - public UiGlobalSelector descStartsWith(String prefix) { - mFilters.add(DescFilter.startsWith(prefix)); - return this; - } - - public UiGlobalSelector descEndsWith(String suffix) { - mFilters.add(DescFilter.endsWith(suffix)); - return this; - } - - public UiGlobalSelector descMatches(String regex) { - mFilters.add(DescFilter.matches(regex)); - return this; - } - - public UiGlobalSelector className(String className) { - mFilters.add(ClassNameFilter.equals(className)); - return this; - } - - public UiGlobalSelector classNameContains(String str) { - mFilters.add(ClassNameFilter.contains(str)); - return this; - } - - public UiGlobalSelector classNameStartsWith(String prefix) { - mFilters.add(ClassNameFilter.startsWith(prefix)); - return this; - } - - public UiGlobalSelector classNameEndsWith(String suffix) { - mFilters.add(ClassNameFilter.endsWith(suffix)); - return this; - } - - public UiGlobalSelector classNameMatches(String regex) { - mFilters.add(ClassNameFilter.matches(regex)); - return this; - } - - public UiGlobalSelector packageName(String packageName) { - mFilters.add(PackageNameFilter.equals(packageName)); - return this; - } - - public UiGlobalSelector packageNameContains(String str) { - mFilters.add(PackageNameFilter.contains(str)); - return this; - } - - public UiGlobalSelector packageNameStartsWith(String prefix) { - mFilters.add(PackageNameFilter.startsWith(prefix)); - return this; - } - - public UiGlobalSelector packageNameEndsWith(String suffix) { - mFilters.add(PackageNameFilter.endsWith(suffix)); - return this; - } - - public UiGlobalSelector packageNameMatches(String regex) { - mFilters.add(PackageNameFilter.matches(regex)); - return this; - } - - public UiGlobalSelector bounds(int l, int t, int r, int b) { - mFilters.add(new BoundsFilter(new Rect(l, t, r, b), BoundsFilter.TYPE_EQUALS)); - return this; - } - - public UiGlobalSelector boundsInside(int l, int t, int r, int b) { - mFilters.add(new BoundsFilter(new Rect(l, t, r, b), BoundsFilter.TYPE_INSIDE)); - return this; - } - - public UiGlobalSelector boundsContains(int l, int t, int r, int b) { - mFilters.add(new BoundsFilter(new Rect(l, t, r, b), BoundsFilter.TYPE_CONTAINS)); - return this; - } - - public UiGlobalSelector drawingOrder(final int order) { - mFilters.add(new DfsFilter() { - @Override - protected boolean isIncluded(UiObject nodeInfo) { - return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && nodeInfo.getDrawingOrder() == order; - } - - @Override - public String toString() { - return "drawingOrder(" + order + ")"; - } - }); - return this; - } - - //// 第二类筛选条件 -able - - public UiGlobalSelector checkable(boolean b) { - mFilters.add(BooleanFilter.get(BooleanFilter.CHECKABLE, b)); - return this; - } - - public UiGlobalSelector checked(boolean b) { - mFilters.add(BooleanFilter.get(BooleanFilter.CHECKED, b)); - return this; - } - - public UiGlobalSelector focusable(boolean b) { - mFilters.add(BooleanFilter.get(BooleanFilter.FOCUSABLE, b)); - return this; - } - - public UiGlobalSelector focused(boolean b) { - mFilters.add(BooleanFilter.get(BooleanFilter.FOCUSED, b)); - return this; - } - - public UiGlobalSelector visibleToUser(boolean b) { - mFilters.add(BooleanFilter.get(BooleanFilter.VISIBLE_TO_USER, b)); - return this; - } - - public UiGlobalSelector accessibilityFocused(boolean b) { - mFilters.add(BooleanFilter.get(BooleanFilter.ACCESSIBILITY_FOCUSED, b)); - return this; - } - - public UiGlobalSelector selected(boolean b) { - mFilters.add(BooleanFilter.get(BooleanFilter.SELECTED, b)); - return this; - } - - public UiGlobalSelector clickable(boolean b) { - mFilters.add(BooleanFilter.get(BooleanFilter.CLICKABLE, b)); - return this; - } - - public UiGlobalSelector longClickable(boolean b) { - mFilters.add(BooleanFilter.get(BooleanFilter.LONG_CLICKABLE, b)); - return this; - } - - public UiGlobalSelector enabled(boolean b) { - mFilters.add(BooleanFilter.get(BooleanFilter.ENABLED, b)); - return this; - } - - public UiGlobalSelector password(boolean b) { - mFilters.add(BooleanFilter.get(BooleanFilter.PASSWORD, b)); - return this; - } - - public UiGlobalSelector scrollable(boolean b) { - mFilters.add(BooleanFilter.get(BooleanFilter.SCROLLABLE, b)); - return this; - } - - public UiGlobalSelector editable(boolean b) { - mFilters.add(BooleanFilter.get(BooleanFilter.EDITABLE, b)); - return this; - } - - public UiGlobalSelector contentInvalid(boolean b) { - mFilters.add(BooleanFilter.get(BooleanFilter.CONTENT_INVALID, b)); - return this; - } - - public UiGlobalSelector contextClickable(boolean b) { - mFilters.add(BooleanFilter.get(BooleanFilter.CONTEXT_CLICKABLE, b)); - return this; - } - - public UiGlobalSelector multiLine(boolean b) { - mFilters.add(BooleanFilter.get(BooleanFilter.MULTI_LINE, b)); - return this; - } - - public UiGlobalSelector dismissable(boolean b) { - mFilters.add(BooleanFilter.get(BooleanFilter.DISMISSABLE, b)); - return this; - } - - public UiGlobalSelector checkable() { - mFilters.add(BooleanFilter.get(BooleanFilter.CHECKABLE, true)); - return this; - } - - public UiGlobalSelector checked() { - mFilters.add(BooleanFilter.get(BooleanFilter.CHECKED, true)); - return this; - } - - public UiGlobalSelector focusable() { - mFilters.add(BooleanFilter.get(BooleanFilter.FOCUSABLE, true)); - return this; - } - - public UiGlobalSelector focused() { - mFilters.add(BooleanFilter.get(BooleanFilter.FOCUSED, true)); - return this; - } - - public UiGlobalSelector visibleToUser() { - mFilters.add(BooleanFilter.get(BooleanFilter.VISIBLE_TO_USER, true)); - return this; - } - - public UiGlobalSelector accessibilityFocused() { - mFilters.add(BooleanFilter.get(BooleanFilter.ACCESSIBILITY_FOCUSED, true)); - return this; - } - - public UiGlobalSelector selected() { - mFilters.add(BooleanFilter.get(BooleanFilter.SELECTED, true)); - return this; - } - - public UiGlobalSelector clickable() { - mFilters.add(BooleanFilter.get(BooleanFilter.CLICKABLE, true)); - return this; - } - - public UiGlobalSelector longClickable() { - mFilters.add(BooleanFilter.get(BooleanFilter.LONG_CLICKABLE, true)); - return this; - } - - public UiGlobalSelector enabled() { - mFilters.add(BooleanFilter.get(BooleanFilter.ENABLED, true)); - return this; - } - - public UiGlobalSelector password() { - mFilters.add(BooleanFilter.get(BooleanFilter.PASSWORD, true)); - return this; - } - - public UiGlobalSelector scrollable() { - mFilters.add(BooleanFilter.get(BooleanFilter.SCROLLABLE, true)); - return this; - } - - public UiGlobalSelector editable() { - mFilters.add(BooleanFilter.get(BooleanFilter.EDITABLE, true)); - return this; - } - - public UiGlobalSelector contentInvalid() { - mFilters.add(BooleanFilter.get(BooleanFilter.CONTENT_INVALID, true)); - return this; - } - - public UiGlobalSelector contextClickable() { - mFilters.add(BooleanFilter.get(BooleanFilter.CONTEXT_CLICKABLE, true)); - return this; - } - - public UiGlobalSelector multiLine() { - mFilters.add(BooleanFilter.get(BooleanFilter.MULTI_LINE, true)); - return this; - } - - public UiGlobalSelector dismissable() { - mFilters.add(BooleanFilter.get(BooleanFilter.DISMISSABLE, true)); - return this; - } - - - //第三类 int - public UiGlobalSelector depth(int d) { - mFilters.add(new IntFilter(IntFilter.DEPTH, d)); - return this; - } - - public UiGlobalSelector row(int d) { - mFilters.add(new IntFilter(IntFilter.ROW, d)); - return this; - } - - public UiGlobalSelector rowCount(int d) { - mFilters.add(new IntFilter(IntFilter.ROW_COUNT, d)); - return this; - } - - public UiGlobalSelector rowSpan(int d) { - mFilters.add(new IntFilter(IntFilter.ROW_SPAN, d)); - return this; - } - - public UiGlobalSelector column(int d) { - mFilters.add(new IntFilter(IntFilter.COLUMN, d)); - return this; - } - - public UiGlobalSelector columnCount(int d) { - mFilters.add(new IntFilter(IntFilter.COLUMN_COUNT, d)); - return this; - } - - public UiGlobalSelector columnSpan(int d) { - mFilters.add(new IntFilter(IntFilter.COLUMN_SPAN, d)); - return this; - } - - public UiGlobalSelector indexInParent(int index) { - mFilters.add(new IntFilter(IntFilter.INDEX_IN_PARENT, index)); - return this; - } - - - public UiGlobalSelector filter(final BooleanFilter.BooleanSupplier filter) { - mFilters.add(new DfsFilter() { - @Override - protected boolean isIncluded(UiObject nodeInfo) { - return filter.get(nodeInfo); - } - }); - return this; - } - - public UiObjectCollection findOf(UiObject node) { - return UiObjectCollection.of(findAndReturnList(node)); - } - - public List findAndReturnList(UiObject node) { - List list = new ArrayList<>(); - list.add(node); - for (ListFilter filter : mFilters) { - list = filter.filter(list); - } - return list; - } - - @Nullable - public UiObject findOneOf(UiObject node) { - // TODO: 2017/3/9 优化 - UiObjectCollection collection = findOf(node); - if (collection.size() == 0) { - return null; - } - return collection.get(0); - } - - public UiGlobalSelector addFilter(ListFilter filter) { - mFilters.add(filter); - return this; - } - - @Override - public String toString() { - StringBuilder str = new StringBuilder(); - for (ListFilter filter : mFilters) { - str.append(filter.toString()).append("."); - } - if(str.length() > 0){ - str.deleteCharAt(str.length() - 1); - } - return str.toString(); - } -} diff --git a/automator/src/main/java/com/stardust/automator/UiGlobalSelector.kt b/automator/src/main/java/com/stardust/automator/UiGlobalSelector.kt new file mode 100644 index 00000000..25463d10 --- /dev/null +++ b/automator/src/main/java/com/stardust/automator/UiGlobalSelector.kt @@ -0,0 +1,445 @@ +package com.stardust.automator + +import android.graphics.Rect +import android.os.Build + +import com.stardust.automator.filter.BooleanFilter +import com.stardust.automator.filter.BoundsFilter +import com.stardust.automator.filter.ClassNameFilter +import com.stardust.automator.filter.DescFilter +import com.stardust.automator.filter.DfsFilter +import com.stardust.automator.filter.IdFilter +import com.stardust.automator.filter.IntFilter +import com.stardust.automator.filter.ListFilter +import com.stardust.automator.filter.PackageNameFilter +import com.stardust.automator.filter.TextFilter +import com.stardust.automator.simple_action.Able +import com.stardust.util.Supplier + +import java.util.ArrayList +import java.util.LinkedList +import java.util.Queue + +/** + * Created by Stardust on 2017/3/8. + */ + +open class UiGlobalSelector { + + private val mFilters = LinkedList() + + //// 第一类筛选条件 + + open fun id(id: String): UiGlobalSelector { + mFilters.add(IdFilter.equals(id)) + return this + } + + fun idContains(str: String): UiGlobalSelector { + mFilters.add(IdFilter.contains(str)) + return this + } + + open fun idStartsWith(prefix: String): UiGlobalSelector { + mFilters.add(IdFilter.startsWith(prefix)) + return this + } + + fun idEndsWith(suffix: String): UiGlobalSelector { + mFilters.add(IdFilter.endsWith(suffix)) + return this + } + + open fun idMatches(regex: String): UiGlobalSelector { + mFilters.add(IdFilter.matches(regex)) + return this + } + + fun text(text: String): UiGlobalSelector { + mFilters.add(TextFilter.equals(text)) + return this + } + + fun textContains(str: String): UiGlobalSelector { + mFilters.add(TextFilter.contains(str)) + return this + } + + fun textStartsWith(prefix: String): UiGlobalSelector { + mFilters.add(TextFilter.startsWith(prefix)) + return this + } + + fun textEndsWith(suffix: String): UiGlobalSelector { + mFilters.add(TextFilter.endsWith(suffix)) + return this + } + + open fun textMatches(regex: String): UiGlobalSelector { + mFilters.add(TextFilter.matches(regex)) + return this + } + + fun desc(desc: String): UiGlobalSelector { + mFilters.add(DescFilter.equals(desc)) + return this + } + + fun descContains(str: String): UiGlobalSelector { + mFilters.add(DescFilter.contains(str)) + return this + } + + fun descStartsWith(prefix: String): UiGlobalSelector { + mFilters.add(DescFilter.startsWith(prefix)) + return this + } + + fun descEndsWith(suffix: String): UiGlobalSelector { + mFilters.add(DescFilter.endsWith(suffix)) + return this + } + + open fun descMatches(regex: String): UiGlobalSelector { + mFilters.add(DescFilter.matches(regex)) + return this + } + + fun className(className: String): UiGlobalSelector { + mFilters.add(ClassNameFilter.equals(className)) + return this + } + + fun classNameContains(str: String): UiGlobalSelector { + mFilters.add(ClassNameFilter.contains(str)) + return this + } + + fun classNameStartsWith(prefix: String): UiGlobalSelector { + mFilters.add(ClassNameFilter.startsWith(prefix)) + return this + } + + fun classNameEndsWith(suffix: String): UiGlobalSelector { + mFilters.add(ClassNameFilter.endsWith(suffix)) + return this + } + + open fun classNameMatches(regex: String): UiGlobalSelector { + mFilters.add(ClassNameFilter.matches(regex)) + return this + } + + fun packageName(packageName: String): UiGlobalSelector { + mFilters.add(PackageNameFilter.equals(packageName)) + return this + } + + fun packageNameContains(str: String): UiGlobalSelector { + mFilters.add(PackageNameFilter.contains(str)) + return this + } + + fun packageNameStartsWith(prefix: String): UiGlobalSelector { + mFilters.add(PackageNameFilter.startsWith(prefix)) + return this + } + + fun packageNameEndsWith(suffix: String): UiGlobalSelector { + mFilters.add(PackageNameFilter.endsWith(suffix)) + return this + } + + open fun packageNameMatches(regex: String): UiGlobalSelector { + mFilters.add(PackageNameFilter.matches(regex)) + return this + } + + fun bounds(l: Int, t: Int, r: Int, b: Int): UiGlobalSelector { + mFilters.add(BoundsFilter(Rect(l, t, r, b), BoundsFilter.TYPE_EQUALS)) + return this + } + + fun boundsInside(l: Int, t: Int, r: Int, b: Int): UiGlobalSelector { + mFilters.add(BoundsFilter(Rect(l, t, r, b), BoundsFilter.TYPE_INSIDE)) + return this + } + + fun boundsContains(l: Int, t: Int, r: Int, b: Int): UiGlobalSelector { + mFilters.add(BoundsFilter(Rect(l, t, r, b), BoundsFilter.TYPE_CONTAINS)) + return this + } + + fun drawingOrder(order: Int): UiGlobalSelector { + mFilters.add(object : DfsFilter() { + override fun isIncluded(nodeInfo: UiObject): Boolean { + return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && nodeInfo.drawingOrder == order + } + + override fun toString(): String { + return "drawingOrder($order)" + } + }) + return this + } + + //// 第二类筛选条件 -able + + fun checkable(b: Boolean): UiGlobalSelector { + mFilters.add(BooleanFilter.get(BooleanFilter.CHECKABLE, b)) + return this + } + + fun checked(b: Boolean): UiGlobalSelector { + mFilters.add(BooleanFilter.get(BooleanFilter.CHECKED, b)) + return this + } + + fun focusable(b: Boolean): UiGlobalSelector { + mFilters.add(BooleanFilter.get(BooleanFilter.FOCUSABLE, b)) + return this + } + + fun focused(b: Boolean): UiGlobalSelector { + mFilters.add(BooleanFilter.get(BooleanFilter.FOCUSED, b)) + return this + } + + fun visibleToUser(b: Boolean): UiGlobalSelector { + mFilters.add(BooleanFilter.get(BooleanFilter.VISIBLE_TO_USER, b)) + return this + } + + fun accessibilityFocused(b: Boolean): UiGlobalSelector { + mFilters.add(BooleanFilter.get(BooleanFilter.ACCESSIBILITY_FOCUSED, b)) + return this + } + + fun selected(b: Boolean): UiGlobalSelector { + mFilters.add(BooleanFilter.get(BooleanFilter.SELECTED, b)) + return this + } + + fun clickable(b: Boolean): UiGlobalSelector { + mFilters.add(BooleanFilter.get(BooleanFilter.CLICKABLE, b)) + return this + } + + fun longClickable(b: Boolean): UiGlobalSelector { + mFilters.add(BooleanFilter.get(BooleanFilter.LONG_CLICKABLE, b)) + return this + } + + fun enabled(b: Boolean): UiGlobalSelector { + mFilters.add(BooleanFilter.get(BooleanFilter.ENABLED, b)) + return this + } + + fun password(b: Boolean): UiGlobalSelector { + mFilters.add(BooleanFilter.get(BooleanFilter.PASSWORD, b)) + return this + } + + fun scrollable(b: Boolean): UiGlobalSelector { + mFilters.add(BooleanFilter.get(BooleanFilter.SCROLLABLE, b)) + return this + } + + fun editable(b: Boolean): UiGlobalSelector { + mFilters.add(BooleanFilter.get(BooleanFilter.EDITABLE, b)) + return this + } + + fun contentInvalid(b: Boolean): UiGlobalSelector { + mFilters.add(BooleanFilter.get(BooleanFilter.CONTENT_INVALID, b)) + return this + } + + fun contextClickable(b: Boolean): UiGlobalSelector { + mFilters.add(BooleanFilter.get(BooleanFilter.CONTEXT_CLICKABLE, b)) + return this + } + + fun multiLine(b: Boolean): UiGlobalSelector { + mFilters.add(BooleanFilter.get(BooleanFilter.MULTI_LINE, b)) + return this + } + + fun dismissable(b: Boolean): UiGlobalSelector { + mFilters.add(BooleanFilter.get(BooleanFilter.DISMISSABLE, b)) + return this + } + + fun checkable(): UiGlobalSelector { + mFilters.add(BooleanFilter.get(BooleanFilter.CHECKABLE, true)) + return this + } + + fun checked(): UiGlobalSelector { + mFilters.add(BooleanFilter.get(BooleanFilter.CHECKED, true)) + return this + } + + fun focusable(): UiGlobalSelector { + mFilters.add(BooleanFilter.get(BooleanFilter.FOCUSABLE, true)) + return this + } + + fun focused(): UiGlobalSelector { + mFilters.add(BooleanFilter.get(BooleanFilter.FOCUSED, true)) + return this + } + + fun visibleToUser(): UiGlobalSelector { + mFilters.add(BooleanFilter.get(BooleanFilter.VISIBLE_TO_USER, true)) + return this + } + + fun accessibilityFocused(): UiGlobalSelector { + mFilters.add(BooleanFilter.get(BooleanFilter.ACCESSIBILITY_FOCUSED, true)) + return this + } + + fun selected(): UiGlobalSelector { + mFilters.add(BooleanFilter.get(BooleanFilter.SELECTED, true)) + return this + } + + fun clickable(): UiGlobalSelector { + mFilters.add(BooleanFilter.get(BooleanFilter.CLICKABLE, true)) + return this + } + + fun longClickable(): UiGlobalSelector { + mFilters.add(BooleanFilter.get(BooleanFilter.LONG_CLICKABLE, true)) + return this + } + + fun enabled(): UiGlobalSelector { + mFilters.add(BooleanFilter.get(BooleanFilter.ENABLED, true)) + return this + } + + fun password(): UiGlobalSelector { + mFilters.add(BooleanFilter.get(BooleanFilter.PASSWORD, true)) + return this + } + + fun scrollable(): UiGlobalSelector { + mFilters.add(BooleanFilter.get(BooleanFilter.SCROLLABLE, true)) + return this + } + + fun editable(): UiGlobalSelector { + mFilters.add(BooleanFilter.get(BooleanFilter.EDITABLE, true)) + return this + } + + fun contentInvalid(): UiGlobalSelector { + mFilters.add(BooleanFilter.get(BooleanFilter.CONTENT_INVALID, true)) + return this + } + + fun contextClickable(): UiGlobalSelector { + mFilters.add(BooleanFilter.get(BooleanFilter.CONTEXT_CLICKABLE, true)) + return this + } + + fun multiLine(): UiGlobalSelector { + mFilters.add(BooleanFilter.get(BooleanFilter.MULTI_LINE, true)) + return this + } + + fun dismissable(): UiGlobalSelector { + mFilters.add(BooleanFilter.get(BooleanFilter.DISMISSABLE, true)) + return this + } + + + //第三类 int + fun depth(d: Int): UiGlobalSelector { + mFilters.add(IntFilter(IntFilter.DEPTH, d)) + return this + } + + fun row(d: Int): UiGlobalSelector { + mFilters.add(IntFilter(IntFilter.ROW, d)) + return this + } + + fun rowCount(d: Int): UiGlobalSelector { + mFilters.add(IntFilter(IntFilter.ROW_COUNT, d)) + return this + } + + fun rowSpan(d: Int): UiGlobalSelector { + mFilters.add(IntFilter(IntFilter.ROW_SPAN, d)) + return this + } + + fun column(d: Int): UiGlobalSelector { + mFilters.add(IntFilter(IntFilter.COLUMN, d)) + return this + } + + fun columnCount(d: Int): UiGlobalSelector { + mFilters.add(IntFilter(IntFilter.COLUMN_COUNT, d)) + return this + } + + fun columnSpan(d: Int): UiGlobalSelector { + mFilters.add(IntFilter(IntFilter.COLUMN_SPAN, d)) + return this + } + + fun indexInParent(index: Int): UiGlobalSelector { + mFilters.add(IntFilter(IntFilter.INDEX_IN_PARENT, index)) + return this + } + + + fun filter(filter: BooleanFilter.BooleanSupplier): UiGlobalSelector { + mFilters.add(object : DfsFilter() { + override fun isIncluded(nodeInfo: UiObject): Boolean { + return filter.get(nodeInfo) + } + }) + return this + } + + fun findOf(node: UiObject): UiObjectCollection { + return UiObjectCollection.of(findAndReturnList(node)) + } + + fun findAndReturnList(node: UiObject): List { + var list: List = listOf(node) + for (filter in mFilters) { + list = filter.filter(list) + } + return list + } + + fun findOneOf(node: UiObject): UiObject? { + // TODO: 2017/3/9 优化 + val collection = findOf(node) + return if (collection.size() == 0) { + null + } else collection.get(0) + } + + fun addFilter(filter: ListFilter): UiGlobalSelector { + mFilters.add(filter) + return this + } + + override fun toString(): String { + val str = StringBuilder() + for (filter in mFilters) { + str.append(filter.toString()).append(".") + } + if (str.isNotEmpty()) { + str.deleteCharAt(str.length - 1) + } + return str.toString() + } +} diff --git a/automator/src/main/java/com/stardust/automator/UiObject.java b/automator/src/main/java/com/stardust/automator/UiObject.java deleted file mode 100644 index e3703366..00000000 --- a/automator/src/main/java/com/stardust/automator/UiObject.java +++ /dev/null @@ -1,458 +0,0 @@ -package com.stardust.automator; - -import android.graphics.Rect; -import android.os.Build; -import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat; -import android.util.Log; -import android.view.accessibility.AccessibilityNodeInfo; - -import com.stardust.view.accessibility.AccessibilityNodeInfoAllocator; -import com.stardust.view.accessibility.AccessibilityNodeInfoHelper; -import com.stardust.view.accessibility.AccessibilityService; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_CONTEXT_CLICK; -import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_DOWN; -import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_LEFT; -import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_RIGHT; -import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_TO_POSITION; -import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_UP; -import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SET_PROGRESS; -import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SHOW_ON_SCREEN; - -/** - * Created by Stardust on 2017/3/9. - */ - -public class UiObject extends AccessibilityNodeInfoCompat { - - public static final int ACTION_APPEND_TEXT = 0x00200001; - - private static final String TAG = "UiObject"; - private static final boolean DEBUG = false; - - - public static UiObject createRoot(AccessibilityNodeInfo root) { - return new UiObject(root, null, 0, -1); - } - - public static UiObject createRoot(AccessibilityNodeInfo root, AccessibilityNodeInfoAllocator allocator) { - return new UiObject(root, allocator, 0, -1); - } - - - private AccessibilityNodeInfoAllocator mAllocator = null; - private String mStackTrace = ""; - private int mDepth = 0; - private final int mIndexInParent; - - public UiObject(Object info) { - this(info, 0, -1); - } - - public UiObject(Object info, AccessibilityNodeInfoAllocator allocator, int depth, int indexInParent) { - super(info); - mDepth = depth; - mAllocator = allocator; - mIndexInParent = indexInParent; - if (DEBUG) - mStackTrace = Arrays.toString(Thread.currentThread().getStackTrace()); - - } - - - public UiObject(Object info, AccessibilityNodeInfoAllocator allocator, int indexInParent) { - this(info, allocator, 0, indexInParent); - } - - public UiObject(Object info, int depth, int indexInParent) { - this(info, null, depth, indexInParent); - } - - @Nullable - public UiObject parent() { - try { - AccessibilityNodeInfoCompat parent = super.getParent(); - if (parent == null) - return null; - return new UiObject(parent.getInfo(), mDepth - 1, -1); - } catch (IllegalStateException e) { - // FIXME: 2017/5/5 - return null; - } - } - - @Nullable - public UiObject child(int i) { - try { - AccessibilityNodeInfoCompat child = super.getChild(i); - if (child == null) - return null; - return new UiObject(child.getInfo(), mDepth + 1, i); - } catch (IllegalStateException e) { - // FIXME: 2017/5/5 - return null; - } - } - - public int indexInParent() { - return mIndexInParent; - } - - public UiObjectCollection find(UiGlobalSelector selector) { - return selector.findOf(this); - } - - public UiObject findOne(UiGlobalSelector selector) { - return selector.findOneOf(this); - } - - public UiObjectCollection children() { - ArrayList list = new ArrayList<>(getChildCount()); - for (int i = 0; i < getChildCount(); i++) { - list.add(child(i)); - } - return UiObjectCollection.of(list); - } - - public int childCount() { - return getChildCount(); - } - - public Rect bounds() { - return AccessibilityNodeInfoHelper.getBoundsInScreen(this); - } - - public Rect boundsInParent() { - return AccessibilityNodeInfoHelper.getBoundsInParent(this); - } - - public int drawingOrder() { - return getDrawingOrder(); - } - - public String id() { - return getViewIdResourceName(); - } - - @NonNull - public String text() { - CharSequence t = getText(); - return t == null ? "" : t.toString(); - } - - @Override - public CharSequence getText() { - if (isPassword()) { - return ""; - } - return super.getText(); - } - - public String desc() { - CharSequence d = getContentDescription(); - return d == null ? null : d.toString(); - } - - public String className() { - CharSequence d = getClassName(); - return d == null ? null : d.toString(); - } - - public String packageName() { - CharSequence d = getPackageName(); - return d == null ? null : d.toString(); - } - - public int depth() { - return mDepth; - } - - public boolean performAction(int action, ActionArgument... arguments) { - Bundle bundle = argumentsToBundle(arguments); - return performAction(action, bundle); - } - - @Override - public boolean performAction(int action, Bundle bundle) { - try { - return super.performAction(action, bundle); - } catch (IllegalStateException e) { - // FIXME: 2017/5/5 - return false; - } - } - - @Override - public boolean performAction(int action) { - try { - return super.performAction(action); - } catch (IllegalStateException e) { - // FIXME: 2017/5/5 - return false; - } - - - } - - - public AccessibilityNodeInfoAllocator getAllocator() { - return mAllocator; - } - - private static Bundle argumentsToBundle(ActionArgument[] arguments) { - Bundle bundle = new Bundle(); - for (ActionArgument arg : arguments) { - arg.putIn(bundle); - } - return bundle; - } - - public boolean click() { - return performAction(ACTION_CLICK); - } - - public boolean longClick() { - return performAction(ACTION_LONG_CLICK); - } - - public boolean accessibilityFocus() { - return performAction(ACTION_ACCESSIBILITY_FOCUS); - } - - public boolean clearAccessibilityFocus() { - return performAction(ACTION_CLEAR_ACCESSIBILITY_FOCUS); - } - - public boolean focus() { - return performAction(ACTION_FOCUS); - } - - public boolean clearFocus() { - return performAction(ACTION_CLEAR_FOCUS); - } - - public boolean copy() { - return performAction(ACTION_COPY); - } - - public boolean paste() { - return performAction(ACTION_PASTE); - } - - public boolean select() { - return performAction(ACTION_SELECT); - } - - public boolean cut() { - return performAction(ACTION_CUT); - } - - public boolean collapse() { - return performAction(ACTION_COLLAPSE); - } - - public boolean expand() { - return performAction(ACTION_EXPAND); - } - - public boolean dismiss() { - return performAction(ACTION_DISMISS); - } - - public boolean show() { - return performAction(ACTION_SHOW_ON_SCREEN.getId()); - } - - public boolean scrollForward() { - return performAction(ACTION_SCROLL_FORWARD); - } - - public boolean scrollBackward() { - return performAction(ACTION_SCROLL_BACKWARD); - } - - public boolean scrollUp() { - return performAction(ACTION_SCROLL_UP.getId()); - } - - public boolean scrollDown() { - return performAction(ACTION_SCROLL_DOWN.getId()); - } - - public boolean scrollLeft() { - return performAction(ACTION_SCROLL_LEFT.getId()); - } - - public boolean scrollRight() { - return performAction(ACTION_SCROLL_RIGHT.getId()); - } - - public boolean contextClick() { - return performAction(ACTION_CONTEXT_CLICK.getId()); - } - - public boolean setSelection(int s, int e) { - return performAction(ACTION_SET_SELECTION, - new ActionArgument.IntActionArgument(ACTION_ARGUMENT_SELECTION_START_INT, s), - new ActionArgument.IntActionArgument(ACTION_ARGUMENT_SELECTION_END_INT, e)); - } - - public boolean setText(String text) { - return performAction(ACTION_SET_TEXT, - new ActionArgument.CharSequenceActionArgument(ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, text)); - } - - public boolean setProgress(float value) { - return performAction(ACTION_SET_PROGRESS.getId(), - new ActionArgument.FloatActionArgument(ACTION_ARGUMENT_PROGRESS_VALUE, value)); - } - - public boolean scrollTo(int row, int column) { - return performAction(ACTION_SCROLL_TO_POSITION.getId(), - new ActionArgument.IntActionArgument(ACTION_ARGUMENT_ROW_INT, row), - new ActionArgument.IntActionArgument(ACTION_ARGUMENT_COLUMN_INT, column)); - } - - @Override - public AccessibilityNodeInfoCompat getChild(int index) { - if (mAllocator == null) - return super.getChild(index); - return mAllocator.getChild(this, index); - } - - @Override - public AccessibilityNodeInfoCompat getParent() { - if (mAllocator == null) - return super.getParent(); - return mAllocator.getParent(this); - } - - - public boolean checkable() { - return isCheckable(); - } - - - public boolean checked() { - return isChecked(); - } - - - public boolean focusable() { - return isFocusable(); - } - - - public boolean focused() { - return isFocused(); - } - - - public boolean visibleToUser() { - return isVisibleToUser(); - } - - - public boolean accessibilityFocused() { - return isAccessibilityFocused(); - } - - - public boolean selected() { - return isSelected(); - } - - public boolean clickable() { - return isClickable(); - } - - - public boolean longClickable() { - return isLongClickable(); - } - - - public boolean enabled() { - return isEnabled(); - } - - - public boolean password() { - return isPassword(); - } - - - public boolean scrollable() { - return isScrollable(); - } - - public int row() { - return getCollectionItemInfo() == null ? -1 : getCollectionItemInfo().getRowIndex(); - } - - public int column() { - return getCollectionItemInfo() == null ? -1 : getCollectionItemInfo().getColumnIndex(); - } - - public int rowSpan() { - return getCollectionItemInfo() == null ? -1 : getCollectionItemInfo().getRowSpan(); - } - - - public int columnSpan() { - return getCollectionItemInfo() == null ? -1 : getCollectionItemInfo().getColumnSpan(); - } - - public int rowCount() { - return getCollectionInfo() == null ? 0 : getCollectionInfo().getRowCount(); - } - - - public int columnCount() { - return getCollectionInfo() == null ? 0 : getCollectionInfo().getColumnCount(); - } - - public boolean isHierarchically() { - return getCollectionInfo() != null && getCollectionInfo().isHierarchical(); - } - - @Override - public List findAccessibilityNodeInfosByText(String text) { - if (mAllocator == null) - return super.findAccessibilityNodeInfosByText(text); - return mAllocator.findAccessibilityNodeInfosByText(this, text); - } - - public List findByText(String text) { - return new UiGlobalSelector().textContains(text).findAndReturnList(this); - } - - @Override - public List findAccessibilityNodeInfosByViewId(String viewId) { - if (mAllocator == null) - return super.findAccessibilityNodeInfosByViewId(viewId); - return mAllocator.findAccessibilityNodeInfosByViewId(this, viewId); - } - - public List findByViewId(String viewId) { - return new UiGlobalSelector().id(viewId).findAndReturnList(this); - } - - @Override - public void recycle() { - try { - super.recycle(); - } catch (Exception e) { - Log.w(TAG, mStackTrace, e); - } - } - - -} diff --git a/automator/src/main/java/com/stardust/automator/UiObject.kt b/automator/src/main/java/com/stardust/automator/UiObject.kt new file mode 100644 index 00000000..6390cf76 --- /dev/null +++ b/automator/src/main/java/com/stardust/automator/UiObject.kt @@ -0,0 +1,420 @@ +package com.stardust.automator + +import android.graphics.Rect +import android.os.Build +import android.os.Bundle +import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat +import android.util.Log +import android.view.accessibility.AccessibilityNodeInfo + +import com.stardust.view.accessibility.AccessibilityNodeInfoAllocator +import com.stardust.view.accessibility.AccessibilityNodeInfoHelper +import com.stardust.view.accessibility.AccessibilityService + +import java.util.ArrayList +import java.util.Arrays + +import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_CONTEXT_CLICK +import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_DOWN +import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_LEFT +import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_RIGHT +import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_TO_POSITION +import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_UP +import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SET_PROGRESS +import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SHOW_ON_SCREEN + +/** + * Created by Stardust on 2017/3/9. + */ + +open class UiObject(info: Any?, private val allocator: AccessibilityNodeInfoAllocator?, depth: Int, private val mIndexInParent: Int) : AccessibilityNodeInfoCompat(info) { + + + private var mStackTrace = "" + private var mDepth = 0 + + val isHierarchically: Boolean + get() = collectionInfo != null && collectionInfo.isHierarchical + + init { + mDepth = depth + if (DEBUG) + mStackTrace = Arrays.toString(Thread.currentThread().stackTrace) + + } + + + constructor(info: Any?, allocator: AccessibilityNodeInfoAllocator, indexInParent: Int) : this(info, allocator, 0, indexInParent) {} + + @JvmOverloads + constructor(info: Any?, depth: Int = 0, indexInParent: Int = -1) : this(info, null, depth, indexInParent) + + open fun parent(): UiObject? { + try { + val parent = super.getParent() ?: return null + return UiObject(parent.info, mDepth - 1, -1) + } catch (e: IllegalStateException) { + // FIXME: 2017/5/5 + return null + } + + } + + open fun child(i: Int): UiObject? { + try { + val child = super.getChild(i) ?: return null + return UiObject(child.info, mDepth + 1, i) + } catch (e: IllegalStateException) { + // FIXME: 2017/5/5 + return null + } + + } + + fun indexInParent(): Int { + return mIndexInParent + } + + fun find(selector: UiGlobalSelector): UiObjectCollection { + return selector.findOf(this) + } + + fun findOne(selector: UiGlobalSelector): UiObject? { + return selector.findOneOf(this) + } + + fun children(): UiObjectCollection { + val list = ArrayList(childCount) + for (i in 0 until childCount) { + list.add(child(i)) + } + return UiObjectCollection.of(list) + } + + open fun childCount(): Int { + return childCount + } + + open fun bounds(): Rect { + return AccessibilityNodeInfoHelper.getBoundsInScreen(this) + } + + open fun boundsInParent(): Rect { + return AccessibilityNodeInfoHelper.getBoundsInParent(this) + } + + open fun drawingOrder(): Int { + return drawingOrder + } + + open fun id(): String { + return viewIdResourceName + } + + open fun text(): String { + val t = text + return t?.toString() ?: "" + } + + override fun getText(): CharSequence? { + return if (isPassword) { + "" + } else super.getText() + } + + open fun desc(): String? { + val d = contentDescription + return d?.toString() + } + + open fun className(): String? { + val d = className + return d?.toString() + } + + open fun packageName(): String? { + val d = packageName + return d?.toString() + } + + open fun depth(): Int { + return mDepth + } + + fun performAction(action: Int, vararg arguments: ActionArgument): Boolean { + val bundle = argumentsToBundle(arguments) + return performAction(action, bundle) + } + + override fun performAction(action: Int, bundle: Bundle): Boolean { + try { + return super.performAction(action, bundle) + } catch (e: IllegalStateException) { + // FIXME: 2017/5/5 + return false + } + + } + + override fun performAction(action: Int): Boolean { + try { + return super.performAction(action) + } catch (e: IllegalStateException) { + // FIXME: 2017/5/5 + return false + } + + + } + + fun click(): Boolean { + return performAction(AccessibilityNodeInfoCompat.ACTION_CLICK) + } + + fun longClick(): Boolean { + return performAction(AccessibilityNodeInfoCompat.ACTION_LONG_CLICK) + } + + fun accessibilityFocus(): Boolean { + return performAction(AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS) + } + + fun clearAccessibilityFocus(): Boolean { + return performAction(AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS) + } + + fun focus(): Boolean { + return performAction(AccessibilityNodeInfoCompat.ACTION_FOCUS) + } + + fun clearFocus(): Boolean { + return performAction(AccessibilityNodeInfoCompat.ACTION_CLEAR_FOCUS) + } + + fun copy(): Boolean { + return performAction(AccessibilityNodeInfoCompat.ACTION_COPY) + } + + fun paste(): Boolean { + return performAction(AccessibilityNodeInfoCompat.ACTION_PASTE) + } + + fun select(): Boolean { + return performAction(AccessibilityNodeInfoCompat.ACTION_SELECT) + } + + fun cut(): Boolean { + return performAction(AccessibilityNodeInfoCompat.ACTION_CUT) + } + + fun collapse(): Boolean { + return performAction(AccessibilityNodeInfoCompat.ACTION_COLLAPSE) + } + + fun expand(): Boolean { + return performAction(AccessibilityNodeInfoCompat.ACTION_EXPAND) + } + + fun dismiss(): Boolean { + return performAction(AccessibilityNodeInfoCompat.ACTION_DISMISS) + } + + fun show(): Boolean { + return performAction(ACTION_SHOW_ON_SCREEN.id) + } + + fun scrollForward(): Boolean { + return performAction(AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD) + } + + fun scrollBackward(): Boolean { + return performAction(AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD) + } + + fun scrollUp(): Boolean { + return performAction(ACTION_SCROLL_UP.id) + } + + fun scrollDown(): Boolean { + return performAction(ACTION_SCROLL_DOWN.id) + } + + fun scrollLeft(): Boolean { + return performAction(ACTION_SCROLL_LEFT.id) + } + + fun scrollRight(): Boolean { + return performAction(ACTION_SCROLL_RIGHT.id) + } + + fun contextClick(): Boolean { + return performAction(ACTION_CONTEXT_CLICK.id) + } + + fun setSelection(s: Int, e: Int): Boolean { + return performAction(AccessibilityNodeInfoCompat.ACTION_SET_SELECTION, + ActionArgument.IntActionArgument(AccessibilityNodeInfoCompat.ACTION_ARGUMENT_SELECTION_START_INT, s), + ActionArgument.IntActionArgument(AccessibilityNodeInfoCompat.ACTION_ARGUMENT_SELECTION_END_INT, e)) + } + + fun setText(text: String): Boolean { + return performAction(AccessibilityNodeInfoCompat.ACTION_SET_TEXT, + ActionArgument.CharSequenceActionArgument(AccessibilityNodeInfoCompat.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, text)) + } + + fun setProgress(value: Float): Boolean { + return performAction(ACTION_SET_PROGRESS.id, + ActionArgument.FloatActionArgument(AccessibilityNodeInfoCompat.ACTION_ARGUMENT_PROGRESS_VALUE, value)) + } + + fun scrollTo(row: Int, column: Int): Boolean { + return performAction(ACTION_SCROLL_TO_POSITION.id, + ActionArgument.IntActionArgument(AccessibilityNodeInfoCompat.ACTION_ARGUMENT_ROW_INT, row), + ActionArgument.IntActionArgument(AccessibilityNodeInfoCompat.ACTION_ARGUMENT_COLUMN_INT, column)) + } + + override fun getChild(index: Int): AccessibilityNodeInfoCompat { + return if (allocator == null) super.getChild(index) else allocator.getChild(this, index) + } + + override fun getParent(): AccessibilityNodeInfoCompat { + return if (allocator == null) super.getParent() else allocator.getParent(this) + } + + + open fun checkable(): Boolean { + return isCheckable + } + + + open fun checked(): Boolean { + return isChecked + } + + + open fun focusable(): Boolean { + return isFocusable + } + + + open fun focused(): Boolean { + return isFocused + } + + + open fun visibleToUser(): Boolean { + return isVisibleToUser + } + + + open fun accessibilityFocused(): Boolean { + return isAccessibilityFocused + } + + + open fun selected(): Boolean { + return isSelected + } + + open fun clickable(): Boolean { + return isClickable + } + + + open fun longClickable(): Boolean { + return isLongClickable + } + + + open fun enabled(): Boolean { + return isEnabled + } + + + fun password(): Boolean { + return isPassword + } + + + open fun scrollable(): Boolean { + return isScrollable + } + + open fun row(): Int { + return if (collectionItemInfo == null) -1 else collectionItemInfo.rowIndex + } + + open fun column(): Int { + return if (collectionItemInfo == null) -1 else collectionItemInfo.columnIndex + } + + open fun rowSpan(): Int { + return if (collectionItemInfo == null) -1 else collectionItemInfo.rowSpan + } + + + open fun columnSpan(): Int { + return if (collectionItemInfo == null) -1 else collectionItemInfo.columnSpan + } + + open fun rowCount(): Int { + return if (collectionInfo == null) 0 else collectionInfo.rowCount + } + + + open fun columnCount(): Int { + return if (collectionInfo == null) 0 else collectionInfo.columnCount + } + + override fun findAccessibilityNodeInfosByText(text: String): List { + return if (allocator == null) super.findAccessibilityNodeInfosByText(text) else allocator.findAccessibilityNodeInfosByText(this, text) + } + + fun findByText(text: String): List { + return UiGlobalSelector().textContains(text).findAndReturnList(this) + } + + override fun findAccessibilityNodeInfosByViewId(viewId: String): List { + return if (allocator == null) super.findAccessibilityNodeInfosByViewId(viewId) else allocator.findAccessibilityNodeInfosByViewId(this, viewId) + } + + fun findByViewId(viewId: String): List { + return UiGlobalSelector().id(viewId).findAndReturnList(this) + } + + override fun recycle() { + try { + super.recycle() + } catch (e: Exception) { + Log.w(TAG, mStackTrace, e) + } + + } + + companion object { + + val ACTION_APPEND_TEXT = 0x00200001 + + private const val TAG = "UiObject" + private const val DEBUG = false + + + fun createRoot(root: AccessibilityNodeInfo): UiObject { + return UiObject(root, null, 0, -1) + } + + fun createRoot(root: AccessibilityNodeInfo, allocator: AccessibilityNodeInfoAllocator?): UiObject { + return UiObject(root, allocator, 0, -1) + } + + private fun argumentsToBundle(arguments: Array): Bundle { + val bundle = Bundle() + for (arg in arguments) { + arg.putIn(bundle) + } + return bundle + } + } + + +} diff --git a/automator/src/main/java/com/stardust/automator/UiObjectCollection.java b/automator/src/main/java/com/stardust/automator/UiObjectCollection.java deleted file mode 100644 index 4cf6de1b..00000000 --- a/automator/src/main/java/com/stardust/automator/UiObjectCollection.java +++ /dev/null @@ -1,324 +0,0 @@ -package com.stardust.automator; - -import android.os.Bundle; -import android.support.annotation.Nullable; - -import com.stardust.util.Consumer; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; - -import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS; -import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_COLUMN_INT; -import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_PROGRESS_VALUE; -import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_ROW_INT; -import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_SELECTION_END_INT; -import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_SELECTION_START_INT; -import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE; -import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS; -import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_CLEAR_FOCUS; -import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_CLICK; -import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_COLLAPSE; -import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_COPY; -import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_CUT; -import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_DISMISS; -import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_EXPAND; -import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_FOCUS; -import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_LONG_CLICK; -import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_PASTE; -import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD; -import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD; -import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_SELECT; -import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_SET_SELECTION; -import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_SET_TEXT; -import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_CONTEXT_CLICK; -import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_DOWN; -import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_LEFT; -import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_RIGHT; -import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_TO_POSITION; -import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_UP; -import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SET_PROGRESS; -import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SHOW_ON_SCREEN; - -/** - * Created by Stardust on 2017/3/9. - */ - -public class UiObjectCollection { - - public static final UiObjectCollection EMPTY = UiObjectCollection.of(Collections.emptyList()); - - public static UiObjectCollection of(List list) { - return new UiObjectCollection(list); - } - - private List mNodes; - - private UiObjectCollection(List list) { - mNodes = list; - } - - public UiObject[] toArray() { - return mNodes.toArray(new UiObject[0]); - } - - public T[] toArray(T[] a) { - return mNodes.toArray(a); - } - - public boolean add(UiObject uiObject) { - return mNodes.add(uiObject); - } - - public boolean remove(Object o) { - return mNodes.remove(o); - } - - public boolean containsAll(Collection c) { - return mNodes.containsAll(c); - } - - - public boolean addAll(Collection c) { - return mNodes.addAll(c); - } - - - public boolean addAll(int index, Collection c) { - return mNodes.addAll(index, c); - } - - - public boolean removeAll(Collection c) { - return mNodes.removeAll(c); - } - - - public boolean retainAll(Collection c) { - return mNodes.retainAll(c); - } - - public void clear() { - mNodes.clear(); - } - - public boolean performAction(int action) { - boolean fail = false; - for (UiObject node : mNodes) { - if (!node.performAction(action)) { - fail = true; - } - } - return !fail; - } - - public boolean performAction(int action, ActionArgument... arguments) { - boolean fail = false; - Bundle bundle = argumentsToBundle(arguments); - for (UiObject node : mNodes) { - if (!node.performAction(action, bundle)) { - fail = true; - } - } - return !fail; - } - - private Bundle argumentsToBundle(ActionArgument[] arguments) { - Bundle bundle = new Bundle(); - for (ActionArgument arg : arguments) { - arg.putIn(bundle); - } - return bundle; - } - - public boolean click() { - return performAction(ACTION_CLICK); - } - - public boolean longClick() { - return performAction(ACTION_LONG_CLICK); - } - - public boolean accessibilityFocus() { - return performAction(ACTION_ACCESSIBILITY_FOCUS); - } - - public boolean clearAccessibilityFocus() { - return performAction(ACTION_CLEAR_ACCESSIBILITY_FOCUS); - } - - public boolean focus() { - return performAction(ACTION_FOCUS); - } - - public boolean clearFocus() { - return performAction(ACTION_CLEAR_FOCUS); - } - - public boolean copy() { - return performAction(ACTION_COPY); - } - - public boolean paste() { - return performAction(ACTION_PASTE); - } - - public boolean select() { - return performAction(ACTION_SELECT); - } - - public boolean cut() { - return performAction(ACTION_CUT); - } - - public boolean collapse() { - return performAction(ACTION_COLLAPSE); - } - - public boolean expand() { - return performAction(ACTION_EXPAND); - } - - public boolean dismiss() { - return performAction(ACTION_DISMISS); - } - - public boolean show() { - return performAction(ACTION_SHOW_ON_SCREEN.getId()); - } - - public boolean scrollForward() { - return performAction(ACTION_SCROLL_FORWARD); - } - - public boolean scrollBackward() { - return performAction(ACTION_SCROLL_BACKWARD); - } - - public boolean scrollUp() { - return performAction(ACTION_SCROLL_UP.getId()); - } - - public boolean scrollDown() { - return performAction(ACTION_SCROLL_DOWN.getId()); - } - - public boolean scrollLeft() { - return performAction(ACTION_SCROLL_LEFT.getId()); - } - - public boolean scrollRight() { - return performAction(ACTION_SCROLL_RIGHT.getId()); - } - - public boolean contextClick() { - return performAction(ACTION_CONTEXT_CLICK.getId()); - } - - public boolean setSelection(int s, int e) { - return performAction(ACTION_SET_SELECTION, - new ActionArgument.IntActionArgument(ACTION_ARGUMENT_SELECTION_START_INT, s), - new ActionArgument.IntActionArgument(ACTION_ARGUMENT_SELECTION_END_INT, e)); - } - - public boolean setText(CharSequence text) { - return performAction(ACTION_SET_TEXT, - new ActionArgument.CharSequenceActionArgument(ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, text)); - } - - public boolean setProgress(float value) { - return performAction(ACTION_SET_PROGRESS.getId(), - new ActionArgument.FloatActionArgument(ACTION_ARGUMENT_PROGRESS_VALUE, value)); - - } - - public boolean scrollTo(int row, int column) { - return performAction(ACTION_SCROLL_TO_POSITION.getId(), - new ActionArgument.IntActionArgument(ACTION_ARGUMENT_ROW_INT, row), - new ActionArgument.IntActionArgument(ACTION_ARGUMENT_COLUMN_INT, column)); - } - - public UiObject get(int i) { - return mNodes.get(i); - } - - - public UiObject set(int index, UiObject element) { - return mNodes.set(index, element); - } - - - public void add(int index, UiObject element) { - mNodes.add(index, element); - } - - - public UiObject remove(int index) { - return mNodes.remove(index); - } - - - public int indexOf(Object o) { - return mNodes.indexOf(o); - } - - - public int lastIndexOf(Object o) { - return mNodes.lastIndexOf(o); - } - - public int size() { - return mNodes.size(); - } - - - public boolean isEmpty() { - return mNodes.isEmpty(); - } - - - public boolean contains(Object o) { - return mNodes.contains(o); - } - - public Iterator iterator() { - return mNodes.iterator(); - } - - public UiObjectCollection each(Consumer consumer) { - for (UiObject uiObject : mNodes) { - consumer.accept(uiObject); - } - return this; - } - - public UiObjectCollection find(UiGlobalSelector selector) { - List list = new ArrayList<>(); - for (UiObject object : mNodes) { - list.addAll(selector.findOf(object).mNodes); - } - return of(list); - } - - @Nullable - public UiObject findOne(UiGlobalSelector selector) { - for (UiObject object : mNodes) { - UiObject result = selector.findOneOf(object); - if (result != null) - return result; - } - return null; - } - - public boolean empty() { - return size() == 0; - } - - public boolean nonEmpty() { - return size() != 0; - } - -} diff --git a/automator/src/main/java/com/stardust/automator/UiObjectCollection.kt b/automator/src/main/java/com/stardust/automator/UiObjectCollection.kt new file mode 100644 index 00000000..1356a3eb --- /dev/null +++ b/automator/src/main/java/com/stardust/automator/UiObjectCollection.kt @@ -0,0 +1,263 @@ +package com.stardust.automator + +import android.os.Bundle + +import com.stardust.util.Consumer + +import java.util.ArrayList +import java.util.Collections + +import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS +import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_COLUMN_INT +import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_PROGRESS_VALUE +import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_ROW_INT +import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_SELECTION_END_INT +import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_SELECTION_START_INT +import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE +import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS +import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_CLEAR_FOCUS +import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_CLICK +import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_COLLAPSE +import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_COPY +import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_CUT +import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_DISMISS +import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_EXPAND +import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_FOCUS +import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_LONG_CLICK +import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_PASTE +import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD +import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD +import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_SELECT +import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_SET_SELECTION +import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_SET_TEXT +import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_CONTEXT_CLICK +import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_DOWN +import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_LEFT +import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_RIGHT +import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_TO_POSITION +import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_UP +import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SET_PROGRESS +import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SHOW_ON_SCREEN + +/** + * Created by Stardust on 2017/3/9. + */ + +class UiObjectCollection private constructor(private val mNodes: List) { + + + val isEmpty: Boolean + get() = mNodes.isEmpty() + + fun toArray(): Array { + return mNodes.toTypedArray() + } + + fun performAction(action: Int): Boolean { + var fail = false + for (node in mNodes) { + val succeed = node?.performAction(action) ?: false + if (!succeed) { + fail = true + } + } + return !fail + } + + fun performAction(action: Int, vararg arguments: ActionArgument): Boolean { + var fail = false + val bundle = argumentsToBundle(arguments) + for (node in mNodes) { + val succeed = node?.performAction(action, bundle) ?: false + if (succeed) { + fail = true + } + } + return !fail + } + + private fun argumentsToBundle(arguments: Array): Bundle { + val bundle = Bundle() + for (arg in arguments) { + arg.putIn(bundle) + } + return bundle + } + + fun click(): Boolean { + return performAction(ACTION_CLICK) + } + + fun longClick(): Boolean { + return performAction(ACTION_LONG_CLICK) + } + + fun accessibilityFocus(): Boolean { + return performAction(ACTION_ACCESSIBILITY_FOCUS) + } + + fun clearAccessibilityFocus(): Boolean { + return performAction(ACTION_CLEAR_ACCESSIBILITY_FOCUS) + } + + fun focus(): Boolean { + return performAction(ACTION_FOCUS) + } + + fun clearFocus(): Boolean { + return performAction(ACTION_CLEAR_FOCUS) + } + + fun copy(): Boolean { + return performAction(ACTION_COPY) + } + + fun paste(): Boolean { + return performAction(ACTION_PASTE) + } + + fun select(): Boolean { + return performAction(ACTION_SELECT) + } + + fun cut(): Boolean { + return performAction(ACTION_CUT) + } + + fun collapse(): Boolean { + return performAction(ACTION_COLLAPSE) + } + + fun expand(): Boolean { + return performAction(ACTION_EXPAND) + } + + fun dismiss(): Boolean { + return performAction(ACTION_DISMISS) + } + + fun show(): Boolean { + return performAction(ACTION_SHOW_ON_SCREEN.id) + } + + fun scrollForward(): Boolean { + return performAction(ACTION_SCROLL_FORWARD) + } + + fun scrollBackward(): Boolean { + return performAction(ACTION_SCROLL_BACKWARD) + } + + fun scrollUp(): Boolean { + return performAction(ACTION_SCROLL_UP.id) + } + + fun scrollDown(): Boolean { + return performAction(ACTION_SCROLL_DOWN.id) + } + + fun scrollLeft(): Boolean { + return performAction(ACTION_SCROLL_LEFT.id) + } + + fun scrollRight(): Boolean { + return performAction(ACTION_SCROLL_RIGHT.id) + } + + fun contextClick(): Boolean { + return performAction(ACTION_CONTEXT_CLICK.id) + } + + fun setSelection(s: Int, e: Int): Boolean { + return performAction(ACTION_SET_SELECTION, + ActionArgument.IntActionArgument(ACTION_ARGUMENT_SELECTION_START_INT, s), + ActionArgument.IntActionArgument(ACTION_ARGUMENT_SELECTION_END_INT, e)) + } + + fun setText(text: CharSequence): Boolean { + return performAction(ACTION_SET_TEXT, + ActionArgument.CharSequenceActionArgument(ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, text)) + } + + fun setProgress(value: Float): Boolean { + return performAction(ACTION_SET_PROGRESS.id, + ActionArgument.FloatActionArgument(ACTION_ARGUMENT_PROGRESS_VALUE, value)) + + } + + fun scrollTo(row: Int, column: Int): Boolean { + return performAction(ACTION_SCROLL_TO_POSITION.id, + ActionArgument.IntActionArgument(ACTION_ARGUMENT_ROW_INT, row), + ActionArgument.IntActionArgument(ACTION_ARGUMENT_COLUMN_INT, column)) + } + + operator fun get(i: Int): UiObject? { + return mNodes[i] + } + + fun indexOf(o: UiObject?): Int { + return mNodes.indexOf(o) + } + + + fun lastIndexOf(o: UiObject?): Int { + return mNodes.lastIndexOf(o) + } + + fun size(): Int { + return mNodes.size + } + + + operator fun contains(o: UiObject?): Boolean { + return mNodes.contains(o) + } + + operator fun iterator(): Iterator { + return mNodes.iterator() + } + + fun each(consumer: Consumer): UiObjectCollection { + for (uiObject in mNodes) { + consumer.accept(uiObject) + } + return this + } + + fun find(selector: UiGlobalSelector): UiObjectCollection { + val list = ArrayList() + for (`object` in mNodes) { + `object`?.let { + list.addAll(selector.findOf(it).mNodes) + } + } + return of(list) + } + + fun findOne(selector: UiGlobalSelector): UiObject? { + for (`object` in mNodes) { + val result = `object`?.run { selector.findOneOf(this) } + if (result != null) + return result + } + return null + } + + fun empty(): Boolean { + return size() == 0 + } + + fun nonEmpty(): Boolean { + return size() != 0 + } + + companion object { + + val EMPTY = UiObjectCollection.of(emptyList()) + + fun of(list: List): UiObjectCollection { + return UiObjectCollection(list) + } + } + +} diff --git a/automator/src/main/java/com/stardust/automator/filter/BooleanFilter.java b/automator/src/main/java/com/stardust/automator/filter/BooleanFilter.java deleted file mode 100644 index 627d8a0b..00000000 --- a/automator/src/main/java/com/stardust/automator/filter/BooleanFilter.java +++ /dev/null @@ -1,278 +0,0 @@ -package com.stardust.automator.filter; - -import android.os.Build; -import android.support.annotation.RequiresApi; - -import com.stardust.automator.UiObject; - -import java.util.HashMap; -import java.util.Map; - -/** - * Created by Stardust on 2017/3/9. - */ - -public class BooleanFilter extends DfsFilter { - - private static Map cache = new HashMap<>(); - - - public static BooleanFilter get(BooleanSupplier supplier, boolean b) { - BooleanFilter[] booleanFilters = cache.get(supplier); - if (booleanFilters == null) { - booleanFilters = new BooleanFilter[2]; - cache.put(supplier, booleanFilters); - } - int i = b ? 1 : 0; - if (booleanFilters[i] == null) { - booleanFilters[i] = new BooleanFilter(supplier, b); - } - return booleanFilters[i]; - } - - public interface BooleanSupplier { - - boolean get(UiObject node); - - } - - public static final BooleanSupplier CHECKABLE = new BooleanSupplier() { - - @Override - public boolean get(UiObject node) { - return node.isCheckable(); - } - - @Override - public String toString() { - return "checkable"; - } - }; - - public static final BooleanSupplier CHECKED = new BooleanSupplier() { - - @Override - public boolean get(UiObject node) { - return node.isChecked(); - } - - @Override - public String toString() { - return "checked"; - } - }; - - public static final BooleanSupplier FOCUSABLE = new BooleanSupplier() { - - @Override - public boolean get(UiObject node) { - return node.isFocusable(); - } - - @Override - public String toString() { - return "focusable"; - } - }; - - public static final BooleanSupplier FOCUSED = new BooleanSupplier() { - - @Override - public boolean get(UiObject node) { - return node.isFocused(); - } - - @Override - public String toString() { - return "focused"; - } - }; - - public static final BooleanSupplier VISIBLE_TO_USER = new BooleanSupplier() { - - @Override - public boolean get(UiObject node) { - return node.isVisibleToUser(); - } - - @Override - public String toString() { - return "visibleToUser"; - } - }; - - public static final BooleanSupplier ACCESSIBILITY_FOCUSED = new BooleanSupplier() { - - @Override - public boolean get(UiObject node) { - return node.isAccessibilityFocused(); - } - - @Override - public String toString() { - return "accessibilityFocused"; - } - }; - - public static final BooleanSupplier SELECTED = new BooleanSupplier() { - - @Override - public boolean get(UiObject node) { - return node.isSelected(); - } - - @Override - public String toString() { - return "selected"; - } - }; - - public static final BooleanSupplier CLICKABLE = new BooleanSupplier() { - - @Override - public boolean get(UiObject node) { - return node.isClickable(); - } - - @Override - public String toString() { - return "clickable"; - } - }; - - public static final BooleanSupplier LONG_CLICKABLE = new BooleanSupplier() { - - @Override - public boolean get(UiObject node) { - return node.isLongClickable(); - } - - @Override - public String toString() { - return "longClickable"; - } - }; - - public static final BooleanSupplier ENABLED = new BooleanSupplier() { - - @Override - public boolean get(UiObject node) { - return node.isEnabled(); - } - - @Override - public String toString() { - return "enabled"; - } - }; - - - public static final BooleanSupplier PASSWORD = new BooleanSupplier() { - - @Override - public boolean get(UiObject node) { - return node.isPassword(); - } - - @Override - public String toString() { - return "password"; - } - }; - - public static final BooleanSupplier SCROLLABLE = new BooleanSupplier() { - - @Override - public boolean get(UiObject node) { - return node.isScrollable(); - } - - @Override - public String toString() { - return "scrollable"; - } - }; - - public static final BooleanSupplier EDITABLE = new BooleanSupplier() { - - @Override - public boolean get(UiObject node) { - return node.isEditable(); - } - - @Override - public String toString() { - return "editable"; - } - }; - public static final BooleanSupplier CONTENT_INVALID = new BooleanSupplier() { - - @Override - public boolean get(UiObject node) { - return node.isContentInvalid(); - } - - @Override - public String toString() { - return "contentInvalid"; - } - }; - - public static final BooleanSupplier CONTEXT_CLICKABLE = new BooleanSupplier() { - - @RequiresApi(api = Build.VERSION_CODES.M) - @Override - public boolean get(UiObject node) { - return node.isContextClickable(); - } - - @Override - public String toString() { - return "checkable"; - } - }; - - public static final BooleanSupplier MULTI_LINE = new BooleanSupplier() { - - @Override - public boolean get(UiObject node) { - return node.isMultiLine(); - } - - @Override - public String toString() { - return "multiLine"; - } - }; - - public static final BooleanSupplier DISMISSABLE = new BooleanSupplier() { - - @Override - public boolean get(UiObject node) { - return node.isDismissable(); - } - - @Override - public String toString() { - return "dismissable"; - } - }; - - private BooleanSupplier mBooleanSupplier; - private boolean mExceptedValue; - - public BooleanFilter(BooleanSupplier booleanSupplier, boolean exceptedValue) { - mBooleanSupplier = booleanSupplier; - mExceptedValue = exceptedValue; - } - - @Override - protected boolean isIncluded(UiObject nodeInfo) { - return nodeInfo != null && mBooleanSupplier.get(nodeInfo) == mExceptedValue; - } - - @Override - public String toString() { - return mBooleanSupplier.toString() + "(" + mExceptedValue + ")"; - } -} diff --git a/automator/src/main/java/com/stardust/automator/filter/BooleanFilter.kt b/automator/src/main/java/com/stardust/automator/filter/BooleanFilter.kt new file mode 100644 index 00000000..bbfe477c --- /dev/null +++ b/automator/src/main/java/com/stardust/automator/filter/BooleanFilter.kt @@ -0,0 +1,234 @@ +package com.stardust.automator.filter + +import android.os.Build +import android.support.annotation.RequiresApi + +import com.stardust.automator.UiObject + +import java.util.HashMap + +/** + * Created by Stardust on 2017/3/9. + */ + +class BooleanFilter(private val mBooleanSupplier: BooleanSupplier, private val mExceptedValue: Boolean) : DfsFilter() { + + interface BooleanSupplier { + + operator fun get(node: UiObject): Boolean + + } + + override fun isIncluded(nodeInfo: UiObject): Boolean { + return mBooleanSupplier[nodeInfo] == mExceptedValue + } + + override fun toString(): String { + return mBooleanSupplier.toString() + "(" + mExceptedValue + ")" + } + + companion object { + + private val cache = HashMap>() + + operator fun get(supplier: BooleanSupplier, b: Boolean): BooleanFilter { + var booleanFilters: Array? = cache[supplier] + if (booleanFilters == null) { + booleanFilters = Array(2) { + BooleanFilter(supplier, it != 0) + } + cache[supplier] = booleanFilters + } + val i = if (b) 1 else 0 + return booleanFilters[i] + } + + val CHECKABLE: BooleanSupplier = object : BooleanSupplier { + + override fun get(node: UiObject): Boolean { + return node.isCheckable + } + + override fun toString(): String { + return "checkable" + } + } + + val CHECKED: BooleanSupplier = object : BooleanSupplier { + + override fun get(node: UiObject): Boolean { + return node.isChecked + } + + override fun toString(): String { + return "checked" + } + } + + val FOCUSABLE: BooleanSupplier = object : BooleanSupplier { + + override fun get(node: UiObject): Boolean { + return node.isFocusable + } + + override fun toString(): String { + return "focusable" + } + } + + val FOCUSED: BooleanSupplier = object : BooleanSupplier { + + override fun get(node: UiObject): Boolean { + return node.isFocused + } + + override fun toString(): String { + return "focused" + } + } + + val VISIBLE_TO_USER: BooleanSupplier = object : BooleanSupplier { + + override fun get(node: UiObject): Boolean { + return node.isVisibleToUser + } + + override fun toString(): String { + return "visibleToUser" + } + } + + val ACCESSIBILITY_FOCUSED: BooleanSupplier = object : BooleanSupplier { + + override fun get(node: UiObject): Boolean { + return node.isAccessibilityFocused + } + + override fun toString(): String { + return "accessibilityFocused" + } + } + + val SELECTED: BooleanSupplier = object : BooleanSupplier { + + override fun get(node: UiObject): Boolean { + return node.isSelected + } + + override fun toString(): String { + return "selected" + } + } + + val CLICKABLE: BooleanSupplier = object : BooleanSupplier { + + override fun get(node: UiObject): Boolean { + return node.isClickable + } + + override fun toString(): String { + return "clickable" + } + } + + val LONG_CLICKABLE: BooleanSupplier = object : BooleanSupplier { + + override fun get(node: UiObject): Boolean { + return node.isLongClickable + } + + override fun toString(): String { + return "longClickable" + } + } + + val ENABLED: BooleanSupplier = object : BooleanSupplier { + + override fun get(node: UiObject): Boolean { + return node.isEnabled + } + + override fun toString(): String { + return "enabled" + } + } + + + val PASSWORD: BooleanSupplier = object : BooleanSupplier { + + override fun get(node: UiObject): Boolean { + return node.isPassword + } + + override fun toString(): String { + return "password" + } + } + + val SCROLLABLE: BooleanSupplier = object : BooleanSupplier { + + override fun get(node: UiObject): Boolean { + return node.isScrollable + } + + override fun toString(): String { + return "scrollable" + } + } + + val EDITABLE: BooleanSupplier = object : BooleanSupplier { + + override fun get(node: UiObject): Boolean { + return node.isEditable + } + + override fun toString(): String { + return "editable" + } + } + val CONTENT_INVALID: BooleanSupplier = object : BooleanSupplier { + + override fun get(node: UiObject): Boolean { + return node.isContentInvalid + } + + override fun toString(): String { + return "contentInvalid" + } + } + + val CONTEXT_CLICKABLE: BooleanSupplier = object : BooleanSupplier { + + @RequiresApi(api = Build.VERSION_CODES.M) + override fun get(node: UiObject): Boolean { + return node.isContextClickable + } + + override fun toString(): String { + return "checkable" + } + } + + val MULTI_LINE: BooleanSupplier = object : BooleanSupplier { + + override fun get(node: UiObject): Boolean { + return node.isMultiLine + } + + override fun toString(): String { + return "multiLine" + } + } + + val DISMISSABLE: BooleanSupplier = object : BooleanSupplier { + + override fun get(node: UiObject): Boolean { + return node.isDismissable + } + + override fun toString(): String { + return "dismissable" + } + } + } +} diff --git a/automator/src/main/java/com/stardust/automator/filter/BoundsFilter.java b/automator/src/main/java/com/stardust/automator/filter/BoundsFilter.java deleted file mode 100644 index 1b243fec..00000000 --- a/automator/src/main/java/com/stardust/automator/filter/BoundsFilter.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.stardust.automator.filter; - -import android.graphics.Rect; - -import com.stardust.automator.UiObject; -import com.stardust.view.accessibility.AccessibilityNodeInfoHelper; - -import java.util.Locale; - -/** - * Created by Stardust on 2017/3/9. - */ - -public class BoundsFilter extends DfsFilter { - - public static final int TYPE_EQUALS = 0; - public static final int TYPE_INSIDE = 1; - public static final int TYPE_CONTAINS = 2; - - private Rect mBounds; - private int mType; - - public BoundsFilter(Rect bounds, int type) { - mBounds = bounds; - mType = type; - } - - @Override - protected boolean isIncluded(UiObject nodeInfo) { - if (mType == TYPE_CONTAINS) { - return AccessibilityNodeInfoHelper.getBoundsInScreen(nodeInfo).contains(mBounds); - } - Rect boundsInScreen = AccessibilityNodeInfoHelper.getBoundsInScreen(nodeInfo); - if (mType == TYPE_EQUALS) - return boundsInScreen.equals(mBounds); - return mBounds.contains(boundsInScreen); - } - - @Override - public String toString() { - return String.format(Locale.getDefault(), "bounds%s(%d, %d, %d, %d)", mType == TYPE_EQUALS ? "" : - mType == TYPE_INSIDE ? "Inside" : "Contains", - mBounds.left, mBounds.top, mBounds.right, mBounds.bottom); - } -} diff --git a/automator/src/main/java/com/stardust/automator/filter/BoundsFilter.kt b/automator/src/main/java/com/stardust/automator/filter/BoundsFilter.kt new file mode 100644 index 00000000..76c74b37 --- /dev/null +++ b/automator/src/main/java/com/stardust/automator/filter/BoundsFilter.kt @@ -0,0 +1,37 @@ +package com.stardust.automator.filter + +import android.graphics.Rect + +import com.stardust.automator.UiObject +import com.stardust.view.accessibility.AccessibilityNodeInfoHelper + +import java.util.Locale + +/** + * Created by Stardust on 2017/3/9. + */ + +class BoundsFilter(private val mBounds: Rect, private val mType: Int) : DfsFilter() { + + override fun isIncluded(nodeInfo: UiObject): Boolean { + if (mType == TYPE_CONTAINS) { + return AccessibilityNodeInfoHelper.getBoundsInScreen(nodeInfo).contains(mBounds) + } + val boundsInScreen = AccessibilityNodeInfoHelper.getBoundsInScreen(nodeInfo) + return if (mType == TYPE_EQUALS) boundsInScreen == mBounds else mBounds.contains(boundsInScreen) + } + + override fun toString(): String { + return String.format(Locale.getDefault(), "bounds%s(%d, %d, %d, %d)", if (mType == TYPE_EQUALS) + "" + else if (mType == TYPE_INSIDE) "Inside" else "Contains", + mBounds.left, mBounds.top, mBounds.right, mBounds.bottom) + } + + companion object { + + const val TYPE_EQUALS = 0 + const val TYPE_INSIDE = 1 + const val TYPE_CONTAINS = 2 + } +} diff --git a/automator/src/main/java/com/stardust/automator/filter/ClassNameFilter.java b/automator/src/main/java/com/stardust/automator/filter/ClassNameFilter.java deleted file mode 100644 index 611646ff..00000000 --- a/automator/src/main/java/com/stardust/automator/filter/ClassNameFilter.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.stardust.automator.filter; - -import com.stardust.automator.UiObject; - -/** - * Created by Stardust on 2017/3/9. - */ - -public class ClassNameFilter { - - private static final KeyGetter CLASS_NAME_GETTER = new KeyGetter() { - @Override - public String getKey(UiObject nodeInfo) { - CharSequence charSequence = nodeInfo.getClassName(); - return charSequence == null ? null : charSequence.toString(); - } - - @Override - public String toString() { - return "className"; - } - }; - - public static ListFilter equals(String text) { - if (!text.contains(".")) { - text = "android.widget." + text; - } - return new StringEqualsFilter(text, CLASS_NAME_GETTER); - } - - public static ListFilter contains(String str) { - return new StringContainsFilter(str, CLASS_NAME_GETTER); - } - - public static ListFilter startsWith(String prefix) { - return new StringStartsWithFilter(prefix, CLASS_NAME_GETTER); - } - - public static ListFilter endsWith(String suffix) { - return new StringEndsWithFilter(suffix, CLASS_NAME_GETTER); - } - - public static ListFilter matches(String regex) { - return new StringMatchesFilter(regex, CLASS_NAME_GETTER); - } - - private ClassNameFilter() { - - } -} diff --git a/automator/src/main/java/com/stardust/automator/filter/ClassNameFilter.kt b/automator/src/main/java/com/stardust/automator/filter/ClassNameFilter.kt new file mode 100644 index 00000000..aa579ed3 --- /dev/null +++ b/automator/src/main/java/com/stardust/automator/filter/ClassNameFilter.kt @@ -0,0 +1,45 @@ +package com.stardust.automator.filter + +import com.stardust.automator.UiObject + +/** + * Created by Stardust on 2017/3/9. + */ + +object ClassNameFilter { + + private val CLASS_NAME_GETTER = object : KeyGetter { + override fun getKey(nodeInfo: UiObject): String? { + val charSequence = nodeInfo.className + return charSequence?.toString() + } + + override fun toString(): String { + return "className" + } + } + + fun equals(text: String): ListFilter { + var text = text + if (!text.contains(".")) { + text = "android.widget.$text" + } + return StringEqualsFilter(text, CLASS_NAME_GETTER) + } + + fun contains(str: String): ListFilter { + return StringContainsFilter(str, CLASS_NAME_GETTER) + } + + fun startsWith(prefix: String): ListFilter { + return StringStartsWithFilter(prefix, CLASS_NAME_GETTER) + } + + fun endsWith(suffix: String): ListFilter { + return StringEndsWithFilter(suffix, CLASS_NAME_GETTER) + } + + fun matches(regex: String): ListFilter { + return StringMatchesFilter(regex, CLASS_NAME_GETTER) + } +} diff --git a/automator/src/main/java/com/stardust/automator/filter/DescFilter.java b/automator/src/main/java/com/stardust/automator/filter/DescFilter.java deleted file mode 100644 index 92517644..00000000 --- a/automator/src/main/java/com/stardust/automator/filter/DescFilter.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.stardust.automator.filter; - -import com.stardust.automator.UiObject; - -/** - * Created by Stardust on 2017/3/9. - */ - -public class DescFilter { - - private static final KeyGetter DESC_GETTER = new KeyGetter() { - @Override - public String getKey(UiObject nodeInfo) { - CharSequence charSequence = nodeInfo.getContentDescription(); - return charSequence == null ? null : charSequence.toString(); - } - - @Override - public String toString() { - return "desc"; - } - }; - - public static ListFilter equals(String text) { - return new StringEqualsFilter(text, DESC_GETTER); - } - - public static ListFilter contains(String str) { - return new StringContainsFilter(str, DESC_GETTER); - } - - public static ListFilter startsWith(String prefix) { - return new StringStartsWithFilter(prefix, DESC_GETTER); - } - - public static ListFilter endsWith(String suffix) { - return new StringEndsWithFilter(suffix, DESC_GETTER); - } - public static ListFilter matches(String regex) { - return new StringMatchesFilter(regex, DESC_GETTER); - } - - private DescFilter(){ - - } -} diff --git a/automator/src/main/java/com/stardust/automator/filter/DescFilter.kt b/automator/src/main/java/com/stardust/automator/filter/DescFilter.kt new file mode 100644 index 00000000..f401df62 --- /dev/null +++ b/automator/src/main/java/com/stardust/automator/filter/DescFilter.kt @@ -0,0 +1,41 @@ +package com.stardust.automator.filter + +import com.stardust.automator.UiObject + +/** + * Created by Stardust on 2017/3/9. + */ + +object DescFilter { + + private val DESC_GETTER = object : KeyGetter { + override fun getKey(nodeInfo: UiObject): String? { + val charSequence = nodeInfo.contentDescription + return charSequence?.toString() + } + + override fun toString(): String { + return "desc" + } + } + + fun equals(text: String): ListFilter { + return StringEqualsFilter(text, DESC_GETTER) + } + + fun contains(str: String): ListFilter { + return StringContainsFilter(str, DESC_GETTER) + } + + fun startsWith(prefix: String): ListFilter { + return StringStartsWithFilter(prefix, DESC_GETTER) + } + + fun endsWith(suffix: String): ListFilter { + return StringEndsWithFilter(suffix, DESC_GETTER) + } + + fun matches(regex: String): ListFilter { + return StringMatchesFilter(regex, DESC_GETTER) + } +} diff --git a/automator/src/main/java/com/stardust/automator/filter/DfsFilter.java b/automator/src/main/java/com/stardust/automator/filter/DfsFilter.java deleted file mode 100644 index d87a1c75..00000000 --- a/automator/src/main/java/com/stardust/automator/filter/DfsFilter.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.stardust.automator.filter; - -import com.stardust.automator.UiObject; - -import java.util.ArrayList; -import java.util.List; - -/** - * Created by Stardust on 2017/3/9. - */ - -public abstract class DfsFilter implements ListFilter, Filter { - - @Override - public List filter(List nodes) { - ArrayList list = new ArrayList<>(); - for (UiObject node : nodes) { - if (isIncluded(node)) { - list.add(node); - } - filterChildren(node, list); - } - return list; - } - - public List filter(UiObject node) { - ArrayList list = new ArrayList<>(); - if (isIncluded(node)) { - list.add(node); - } - filterChildren(node, list); - return list; - } - - private void filterChildren(UiObject parent, List list) { - for (int i = 0; i < parent.getChildCount(); i++) { - UiObject child = parent.child(i); - if (child == null) - continue; - boolean included = isIncluded(child); - if (included) { - list.add(child); - } - filterChildren(child, list); - if (!included) { - child.recycle(); - } - } - } - - protected abstract boolean isIncluded(UiObject nodeInfo); -} diff --git a/automator/src/main/java/com/stardust/automator/filter/DfsFilter.kt b/automator/src/main/java/com/stardust/automator/filter/DfsFilter.kt new file mode 100644 index 00000000..c7b881c2 --- /dev/null +++ b/automator/src/main/java/com/stardust/automator/filter/DfsFilter.kt @@ -0,0 +1,48 @@ +package com.stardust.automator.filter + +import com.stardust.automator.UiObject + +import java.util.ArrayList + +/** + * Created by Stardust on 2017/3/9. + */ + +abstract class DfsFilter : ListFilter, Filter { + + override fun filter(nodes: List): List { + val list = ArrayList() + for (node in nodes) { + if (isIncluded(node)) { + list.add(node) + } + filterChildren(node, list) + } + return list + } + + override fun filter(node: UiObject): List { + val list = ArrayList() + if (isIncluded(node)) { + list.add(node) + } + filterChildren(node, list) + return list + } + + private fun filterChildren(parent: UiObject, list: MutableList) { + for (i in 0 until parent.childCount) { + val child = parent.child(i) ?: continue + val included = isIncluded(child) + if (included) { + list.add(child) + } + filterChildren(child, list) + if (!included) { + child.recycle() + } + } + } + + protected abstract fun isIncluded(nodeInfo: UiObject): Boolean +} diff --git a/automator/src/main/java/com/stardust/automator/filter/Filter.java b/automator/src/main/java/com/stardust/automator/filter/Filter.java deleted file mode 100644 index 6ca42fc1..00000000 --- a/automator/src/main/java/com/stardust/automator/filter/Filter.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.stardust.automator.filter; - -import com.stardust.automator.UiObject; - -import java.util.List; - -/** - * Created by Stardust on 2017/3/9. - */ - -public interface Filter { - - List filter(UiObject node); - -} diff --git a/automator/src/main/java/com/stardust/automator/filter/Filter.kt b/automator/src/main/java/com/stardust/automator/filter/Filter.kt new file mode 100644 index 00000000..7966d58f --- /dev/null +++ b/automator/src/main/java/com/stardust/automator/filter/Filter.kt @@ -0,0 +1,13 @@ +package com.stardust.automator.filter + +import com.stardust.automator.UiObject + +/** + * Created by Stardust on 2017/3/9. + */ + +interface Filter { + + fun filter(node: UiObject): List + +} diff --git a/automator/src/main/java/com/stardust/automator/filter/IdFilter.java b/automator/src/main/java/com/stardust/automator/filter/IdFilter.java deleted file mode 100644 index 36f67f5f..00000000 --- a/automator/src/main/java/com/stardust/automator/filter/IdFilter.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.stardust.automator.filter; - -import com.stardust.automator.UiObject; - -import java.util.List; - -/** - * Created by Stardust on 2017/3/9. - */ - -public class IdFilter { - - public interface FullIdGetter { - String getFullId(String id); - } - - private static final KeyGetter ID_GETTER = new KeyGetter() { - - @Override - public String getKey(UiObject nodeInfo) { - return nodeInfo.getViewIdResourceName(); - } - - @Override - public String toString() { - return "id"; - } - }; - - public static StringEqualsFilter equals(String id) { - return new StringEqualsFilter(id, ID_GETTER); - } - public static StringStartsWithFilter startsWith(String prefix) { - return new StringStartsWithFilter(prefix, ID_GETTER); - } - - public static ListFilter endsWith(String suffix) { - return new StringEndsWithFilter(suffix, ID_GETTER); - } - - public static StringContainsFilter contains(String contains) { - return new StringContainsFilter(contains, ID_GETTER); - } - - public static StringMatchesFilter matches(String regex) { - return new StringMatchesFilter(regex, ID_GETTER); - } - -} diff --git a/automator/src/main/java/com/stardust/automator/filter/IdFilter.kt b/automator/src/main/java/com/stardust/automator/filter/IdFilter.kt new file mode 100644 index 00000000..f7517b09 --- /dev/null +++ b/automator/src/main/java/com/stardust/automator/filter/IdFilter.kt @@ -0,0 +1,46 @@ +package com.stardust.automator.filter + +import com.stardust.automator.UiObject + +/** + * Created by Stardust on 2017/3/9. + */ + +object IdFilter { + + private val ID_GETTER = object : KeyGetter { + + override fun getKey(nodeInfo: UiObject): String { + return nodeInfo.viewIdResourceName + } + + override fun toString(): String { + return "id" + } + } + + interface FullIdGetter { + fun getFullId(id: String): String + } + + fun equals(id: String): StringEqualsFilter { + return StringEqualsFilter(id, ID_GETTER) + } + + fun startsWith(prefix: String): StringStartsWithFilter { + return StringStartsWithFilter(prefix, ID_GETTER) + } + + fun endsWith(suffix: String): ListFilter { + return StringEndsWithFilter(suffix, ID_GETTER) + } + + fun contains(contains: String): StringContainsFilter { + return StringContainsFilter(contains, ID_GETTER) + } + + fun matches(regex: String): StringMatchesFilter { + return StringMatchesFilter(regex, ID_GETTER) + } + +} diff --git a/automator/src/main/java/com/stardust/automator/filter/IntFilter.java b/automator/src/main/java/com/stardust/automator/filter/IntFilter.java deleted file mode 100644 index 18d59dd7..00000000 --- a/automator/src/main/java/com/stardust/automator/filter/IntFilter.java +++ /dev/null @@ -1,128 +0,0 @@ -package com.stardust.automator.filter; - -import com.stardust.automator.UiObject; - -/** - * Created by Stardust on 2017/11/5. - */ - -public class IntFilter extends DfsFilter { - - public interface IntProperty { - int get(UiObject object); - } - - public static final IntProperty DEPTH = new IntProperty() { - @Override - public int get(UiObject object) { - return object.depth(); - } - - @Override - public String toString() { - return "depth"; - } - }; - - public static final IntProperty ROW = new IntProperty() { - @Override - public int get(UiObject object) { - return object.row(); - } - - @Override - public String toString() { - return "row"; - } - }; - - public static final IntProperty ROW_COUNT = new IntProperty() { - @Override - public int get(UiObject object) { - return object.rowCount(); - } - - @Override - public String toString() { - return "rowCount"; - } - }; - - public static final IntProperty ROW_SPAN = new IntProperty() { - @Override - public int get(UiObject object) { - return object.rowSpan(); - } - - @Override - public String toString() { - return "rowSpan"; - } - }; - - public static final IntProperty COLUMN = new IntProperty() { - @Override - public int get(UiObject object) { - return object.column(); - } - - @Override - public String toString() { - return "column"; - } - }; - - public static final IntProperty COLUMN_COUNT = new IntProperty() { - @Override - public int get(UiObject object) { - return object.columnCount(); - } - - @Override - public String toString() { - return "columnCount"; - } - }; - - public static final IntProperty COLUMN_SPAN = new IntProperty() { - @Override - public int get(UiObject object) { - return object.columnSpan(); - } - - @Override - public String toString() { - return "columnSpan"; - } - }; - - public static final IntProperty INDEX_IN_PARENT = new IntProperty() { - @Override - public int get(UiObject object) { - return object.indexInParent(); - } - - @Override - public String toString() { - return "indexInParent"; - } - }; - - private IntProperty mIntProperty; - private int mValue; - - public IntFilter(IntProperty intProperty, int value) { - mIntProperty = intProperty; - mValue = value; - } - - @Override - protected boolean isIncluded(UiObject nodeInfo) { - return mIntProperty.get(nodeInfo) == mValue; - } - - @Override - public String toString() { - return mIntProperty.toString() + "(" + mValue + ")"; - } -} diff --git a/automator/src/main/java/com/stardust/automator/filter/IntFilter.kt b/automator/src/main/java/com/stardust/automator/filter/IntFilter.kt new file mode 100644 index 00000000..875d566f --- /dev/null +++ b/automator/src/main/java/com/stardust/automator/filter/IntFilter.kt @@ -0,0 +1,105 @@ +package com.stardust.automator.filter + +import com.stardust.automator.UiObject + +/** + * Created by Stardust on 2017/11/5. + */ + +class IntFilter(private val mIntProperty: IntProperty, private val mValue: Int) : DfsFilter() { + + interface IntProperty { + operator fun get(`object`: UiObject): Int + } + + override fun isIncluded(nodeInfo: UiObject): Boolean { + return mIntProperty[nodeInfo] == mValue + } + + override fun toString(): String { + return mIntProperty.toString() + "(" + mValue + ")" + } + + companion object { + + val DEPTH: IntProperty = object : IntProperty { + override fun get(`object`: UiObject): Int { + return `object`.depth() + } + + override fun toString(): String { + return "depth" + } + } + + val ROW: IntProperty = object : IntProperty { + override fun get(`object`: UiObject): Int { + return `object`.row() + } + + override fun toString(): String { + return "row" + } + } + + val ROW_COUNT: IntProperty = object : IntProperty { + override fun get(`object`: UiObject): Int { + return `object`.rowCount() + } + + override fun toString(): String { + return "rowCount" + } + } + + val ROW_SPAN: IntProperty = object : IntProperty { + override fun get(`object`: UiObject): Int { + return `object`.rowSpan() + } + + override fun toString(): String { + return "rowSpan" + } + } + + val COLUMN: IntProperty = object : IntProperty { + override fun get(`object`: UiObject): Int { + return `object`.column() + } + + override fun toString(): String { + return "column" + } + } + + val COLUMN_COUNT: IntProperty = object : IntProperty { + override fun get(`object`: UiObject): Int { + return `object`.columnCount() + } + + override fun toString(): String { + return "columnCount" + } + } + + val COLUMN_SPAN: IntProperty = object : IntProperty { + override fun get(`object`: UiObject): Int { + return `object`.columnSpan() + } + + override fun toString(): String { + return "columnSpan" + } + } + + val INDEX_IN_PARENT: IntProperty = object : IntProperty { + override fun get(`object`: UiObject): Int { + return `object`.indexInParent() + } + + override fun toString(): String { + return "indexInParent" + } + } + } +} diff --git a/automator/src/main/java/com/stardust/automator/filter/KeyGetter.java b/automator/src/main/java/com/stardust/automator/filter/KeyGetter.java deleted file mode 100644 index e9ae8e3f..00000000 --- a/automator/src/main/java/com/stardust/automator/filter/KeyGetter.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.stardust.automator.filter; - -import com.stardust.automator.UiObject; - -/** - * Created by Stardust on 2017/3/9. - */ - -public interface KeyGetter { - - String getKey(UiObject nodeInfo); -} diff --git a/automator/src/main/java/com/stardust/automator/filter/KeyGetter.kt b/automator/src/main/java/com/stardust/automator/filter/KeyGetter.kt new file mode 100644 index 00000000..17e8c432 --- /dev/null +++ b/automator/src/main/java/com/stardust/automator/filter/KeyGetter.kt @@ -0,0 +1,12 @@ +package com.stardust.automator.filter + +import com.stardust.automator.UiObject + +/** + * Created by Stardust on 2017/3/9. + */ + +interface KeyGetter { + + fun getKey(nodeInfo: UiObject): String? +} diff --git a/automator/src/main/java/com/stardust/automator/filter/ListFilter.java b/automator/src/main/java/com/stardust/automator/filter/ListFilter.java deleted file mode 100644 index 2a805498..00000000 --- a/automator/src/main/java/com/stardust/automator/filter/ListFilter.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.stardust.automator.filter; - -import com.stardust.automator.UiObject; - -import java.util.ArrayList; -import java.util.List; - -/** - * Created by Stardust on 2017/3/9. - */ - -public interface ListFilter { - - List filter(List nodes); - - abstract class Default implements Filter, ListFilter { - - @Override - public List filter(List nodes) { - List list = new ArrayList<>(); - for (UiObject node : nodes) { - list.addAll(filter(node)); - } - return list; - } - } - -} diff --git a/automator/src/main/java/com/stardust/automator/filter/ListFilter.kt b/automator/src/main/java/com/stardust/automator/filter/ListFilter.kt new file mode 100644 index 00000000..dfd6a5a0 --- /dev/null +++ b/automator/src/main/java/com/stardust/automator/filter/ListFilter.kt @@ -0,0 +1,26 @@ +package com.stardust.automator.filter + +import com.stardust.automator.UiObject + +import java.util.ArrayList + +/** + * Created by Stardust on 2017/3/9. + */ + +interface ListFilter { + + fun filter(nodes: List): List + + abstract class Default : Filter, ListFilter { + + override fun filter(nodes: List): List { + val list = ArrayList() + for (node in nodes) { + list.addAll(filter(node)) + } + return list + } + } + +} diff --git a/automator/src/main/java/com/stardust/automator/filter/PackageNameFilter.java b/automator/src/main/java/com/stardust/automator/filter/PackageNameFilter.java deleted file mode 100644 index 17436b03..00000000 --- a/automator/src/main/java/com/stardust/automator/filter/PackageNameFilter.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.stardust.automator.filter; - -import com.stardust.automator.UiObject; - -/** - * Created by Stardust on 2017/3/9. - */ - -public class PackageNameFilter { - - private static final KeyGetter PACKAGE_NAME_GETTER = new KeyGetter() { - @Override - public String getKey(UiObject nodeInfo) { - CharSequence charSequence = nodeInfo.getPackageName(); - return charSequence == null ? null : charSequence.toString(); - } - - @Override - public String toString() { - return "packageName"; - } - }; - - public static ListFilter equals(String text) { - return new StringEqualsFilter(text, PACKAGE_NAME_GETTER); - } - - public static ListFilter contains(String str) { - return new StringContainsFilter(str, PACKAGE_NAME_GETTER); - } - - public static ListFilter startsWith(String prefix) { - return new StringStartsWithFilter(prefix, PACKAGE_NAME_GETTER); - } - - public static ListFilter endsWith(String suffix) { - return new StringEndsWithFilter(suffix, PACKAGE_NAME_GETTER); - } - - public static ListFilter matches(String regex) { - return new StringMatchesFilter(regex, PACKAGE_NAME_GETTER); - } - - private PackageNameFilter() { - - } -} diff --git a/automator/src/main/java/com/stardust/automator/filter/PackageNameFilter.kt b/automator/src/main/java/com/stardust/automator/filter/PackageNameFilter.kt new file mode 100644 index 00000000..611fd066 --- /dev/null +++ b/automator/src/main/java/com/stardust/automator/filter/PackageNameFilter.kt @@ -0,0 +1,41 @@ +package com.stardust.automator.filter + +import com.stardust.automator.UiObject + +/** + * Created by Stardust on 2017/3/9. + */ + +object PackageNameFilter { + + private val PACKAGE_NAME_GETTER = object : KeyGetter { + override fun getKey(nodeInfo: UiObject): String? { + val charSequence = nodeInfo.packageName + return charSequence?.toString() + } + + override fun toString(): String { + return "packageName" + } + } + + fun equals(text: String): ListFilter { + return StringEqualsFilter(text, PACKAGE_NAME_GETTER) + } + + fun contains(str: String): ListFilter { + return StringContainsFilter(str, PACKAGE_NAME_GETTER) + } + + fun startsWith(prefix: String): ListFilter { + return StringStartsWithFilter(prefix, PACKAGE_NAME_GETTER) + } + + fun endsWith(suffix: String): ListFilter { + return StringEndsWithFilter(suffix, PACKAGE_NAME_GETTER) + } + + fun matches(regex: String): ListFilter { + return StringMatchesFilter(regex, PACKAGE_NAME_GETTER) + } +} diff --git a/automator/src/main/java/com/stardust/automator/filter/StringContainsFilter.java b/automator/src/main/java/com/stardust/automator/filter/StringContainsFilter.java deleted file mode 100644 index 2647cbb0..00000000 --- a/automator/src/main/java/com/stardust/automator/filter/StringContainsFilter.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.stardust.automator.filter; - -import com.stardust.automator.UiObject; - -/** - * Created by Stardust on 2017/3/9. - */ - -public class StringContainsFilter extends DfsFilter { - private final KeyGetter mKeyGetter; - private final String mContains; - - StringContainsFilter(String contains, KeyGetter keyGetter) { - mContains = contains; - mKeyGetter = keyGetter; - } - - @Override - protected boolean isIncluded(UiObject nodeInfo) { - String key = mKeyGetter.getKey(nodeInfo); - return key != null && key.contains(mContains); - } - - @Override - public String toString() { - return mKeyGetter.toString() + "Contains(\"" + mContains + "\")"; - } -} diff --git a/automator/src/main/java/com/stardust/automator/filter/StringContainsFilter.kt b/automator/src/main/java/com/stardust/automator/filter/StringContainsFilter.kt new file mode 100644 index 00000000..b60d07f7 --- /dev/null +++ b/automator/src/main/java/com/stardust/automator/filter/StringContainsFilter.kt @@ -0,0 +1,19 @@ +package com.stardust.automator.filter + +import com.stardust.automator.UiObject + +/** + * Created by Stardust on 2017/3/9. + */ + +class StringContainsFilter internal constructor(private val mContains: String, private val mKeyGetter: KeyGetter) : DfsFilter() { + + override fun isIncluded(nodeInfo: UiObject): Boolean { + val key = mKeyGetter.getKey(nodeInfo) + return key != null && key.contains(mContains) + } + + override fun toString(): String { + return mKeyGetter.toString() + "Contains(\"" + mContains + "\")" + } +} diff --git a/automator/src/main/java/com/stardust/automator/filter/StringEndsWithFilter.java b/automator/src/main/java/com/stardust/automator/filter/StringEndsWithFilter.java deleted file mode 100644 index ee78bebd..00000000 --- a/automator/src/main/java/com/stardust/automator/filter/StringEndsWithFilter.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.stardust.automator.filter; - -import com.stardust.automator.UiObject; - -/** - * Created by Stardust on 2017/3/9. - */ - -public class StringEndsWithFilter extends DfsFilter { - - private final String mSuffix; - private final KeyGetter mKeyGetter; - - public StringEndsWithFilter(String suffix, KeyGetter keyGetter) { - mSuffix = suffix; - mKeyGetter = keyGetter; - } - - @Override - protected boolean isIncluded(UiObject nodeInfo) { - String key = mKeyGetter.getKey(nodeInfo); - return key != null && key.endsWith(mSuffix); - } - - @Override - public String toString() { - return mKeyGetter.toString() + "EndsWith(\"" + mSuffix + "\")"; - } -} diff --git a/automator/src/main/java/com/stardust/automator/filter/StringEndsWithFilter.kt b/automator/src/main/java/com/stardust/automator/filter/StringEndsWithFilter.kt new file mode 100644 index 00000000..7cad7693 --- /dev/null +++ b/automator/src/main/java/com/stardust/automator/filter/StringEndsWithFilter.kt @@ -0,0 +1,19 @@ +package com.stardust.automator.filter + +import com.stardust.automator.UiObject + +/** + * Created by Stardust on 2017/3/9. + */ + +class StringEndsWithFilter(private val mSuffix: String, private val mKeyGetter: KeyGetter) : DfsFilter() { + + override fun isIncluded(nodeInfo: UiObject): Boolean { + val key = mKeyGetter.getKey(nodeInfo) + return key != null && key.endsWith(mSuffix) + } + + override fun toString(): String { + return mKeyGetter.toString() + "EndsWith(\"" + mSuffix + "\")" + } +} diff --git a/automator/src/main/java/com/stardust/automator/filter/StringEqualsFilter.java b/automator/src/main/java/com/stardust/automator/filter/StringEqualsFilter.java deleted file mode 100644 index 27ff9168..00000000 --- a/automator/src/main/java/com/stardust/automator/filter/StringEqualsFilter.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.stardust.automator.filter; - -import com.stardust.automator.UiObject; - -/** - * Created by Stardust on 2017/3/9. - */ - -public class StringEqualsFilter extends DfsFilter { - - private String mValue; - private KeyGetter mKeyGetter; - - public StringEqualsFilter(String value, KeyGetter getter) { - mValue = value; - mKeyGetter = getter; - } - - @Override - protected boolean isIncluded(UiObject nodeInfo) { - String key = mKeyGetter.getKey(nodeInfo); - if (key != null) { - return key.equals(mValue); - } - return false; - } - - @Override - public String toString() { - return mKeyGetter.toString() + "(\"" + mValue + "\")"; - } -} diff --git a/automator/src/main/java/com/stardust/automator/filter/StringEqualsFilter.kt b/automator/src/main/java/com/stardust/automator/filter/StringEqualsFilter.kt new file mode 100644 index 00000000..49510e2d --- /dev/null +++ b/automator/src/main/java/com/stardust/automator/filter/StringEqualsFilter.kt @@ -0,0 +1,21 @@ +package com.stardust.automator.filter + +import com.stardust.automator.UiObject + +/** + * Created by Stardust on 2017/3/9. + */ + +class StringEqualsFilter(private val mValue: String, private val mKeyGetter: KeyGetter) : DfsFilter() { + + override fun isIncluded(nodeInfo: UiObject): Boolean { + val key = mKeyGetter.getKey(nodeInfo) + return if (key != null) { + key == mValue + } else false + } + + override fun toString(): String { + return mKeyGetter.toString() + "(\"" + mValue + "\")" + } +} diff --git a/automator/src/main/java/com/stardust/automator/filter/StringMatchesFilter.java b/automator/src/main/java/com/stardust/automator/filter/StringMatchesFilter.java deleted file mode 100644 index bcab8b4f..00000000 --- a/automator/src/main/java/com/stardust/automator/filter/StringMatchesFilter.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.stardust.automator.filter; - -import com.stardust.automator.UiObject; - -/** - * Created by Stardust on 2017/3/9. - */ - -public class StringMatchesFilter extends DfsFilter { - - private final String mRegex; - private final KeyGetter mKeyGetter; - - StringMatchesFilter(String regex, KeyGetter keyGetter) { - mRegex = regex; - mKeyGetter = keyGetter; - } - - @Override - protected boolean isIncluded(UiObject nodeInfo) { - String key = mKeyGetter.getKey(nodeInfo); - return key != null && key.matches(mRegex); - } - - @Override - public String toString() { - return mKeyGetter.toString() + "Matches(\"" + mRegex + "\")"; - } -} diff --git a/automator/src/main/java/com/stardust/automator/filter/StringMatchesFilter.kt b/automator/src/main/java/com/stardust/automator/filter/StringMatchesFilter.kt new file mode 100644 index 00000000..54814487 --- /dev/null +++ b/automator/src/main/java/com/stardust/automator/filter/StringMatchesFilter.kt @@ -0,0 +1,19 @@ +package com.stardust.automator.filter + +import com.stardust.automator.UiObject + +/** + * Created by Stardust on 2017/3/9. + */ + +class StringMatchesFilter internal constructor(private val mRegex: String, private val mKeyGetter: KeyGetter) : DfsFilter() { + + override fun isIncluded(nodeInfo: UiObject): Boolean { + val key = mKeyGetter.getKey(nodeInfo) + return key != null && key.matches(mRegex.toRegex()) + } + + override fun toString(): String { + return mKeyGetter.toString() + "Matches(\"" + mRegex + "\")" + } +} diff --git a/automator/src/main/java/com/stardust/automator/filter/StringStartsWithFilter.java b/automator/src/main/java/com/stardust/automator/filter/StringStartsWithFilter.java deleted file mode 100644 index 954f0f73..00000000 --- a/automator/src/main/java/com/stardust/automator/filter/StringStartsWithFilter.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.stardust.automator.filter; - -import com.stardust.automator.UiObject; - -/** - * Created by Stardust on 2017/3/9. - */ - -public class StringStartsWithFilter extends DfsFilter { - - private final String mPrefix; - private final KeyGetter mKeyGetter; - - public StringStartsWithFilter(String prefix, KeyGetter keyGetter) { - mPrefix = prefix; - mKeyGetter = keyGetter; - } - - @Override - protected boolean isIncluded(UiObject nodeInfo) { - String key = mKeyGetter.getKey(nodeInfo); - return key != null && key.startsWith(mPrefix); - } - - @Override - public String toString() { - return mKeyGetter.toString() + "StartsWith(\"" + mPrefix + "\")"; - } -} diff --git a/automator/src/main/java/com/stardust/automator/filter/StringStartsWithFilter.kt b/automator/src/main/java/com/stardust/automator/filter/StringStartsWithFilter.kt new file mode 100644 index 00000000..342f0b76 --- /dev/null +++ b/automator/src/main/java/com/stardust/automator/filter/StringStartsWithFilter.kt @@ -0,0 +1,19 @@ +package com.stardust.automator.filter + +import com.stardust.automator.UiObject + +/** + * Created by Stardust on 2017/3/9. + */ + +class StringStartsWithFilter(private val mPrefix: String, private val mKeyGetter: KeyGetter) : DfsFilter() { + + override fun isIncluded(nodeInfo: UiObject): Boolean { + val key = mKeyGetter.getKey(nodeInfo) + return key != null && key.startsWith(mPrefix) + } + + override fun toString(): String { + return mKeyGetter.toString() + "StartsWith(\"" + mPrefix + "\")" + } +} diff --git a/automator/src/main/java/com/stardust/automator/filter/TextFilter.java b/automator/src/main/java/com/stardust/automator/filter/TextFilter.java deleted file mode 100644 index fc87dc12..00000000 --- a/automator/src/main/java/com/stardust/automator/filter/TextFilter.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.stardust.automator.filter; - -import com.stardust.automator.UiObject; - -import java.util.List; - -/** - * Created by Stardust on 2017/3/9. - */ - -public class TextFilter extends ListFilter.Default { - - private static final KeyGetter TEXT_GETTER = new KeyGetter() { - @Override - public String getKey(UiObject nodeInfo) { - CharSequence charSequence = nodeInfo.getText(); - return charSequence == null ? null : charSequence.toString(); - } - - @Override - public String toString() { - return "text"; - } - }; - - public static ListFilter equals(String text) { - return new StringEqualsFilter(text, TEXT_GETTER); - } - - public static ListFilter contains(String str) { - return new StringContainsFilter(str, TEXT_GETTER); - } - - public static ListFilter startsWith(String prefix) { - return new StringStartsWithFilter(prefix, TEXT_GETTER); - } - - public static ListFilter endsWith(String suffix) { - return new StringEndsWithFilter(suffix, TEXT_GETTER); - } - - public static ListFilter matches(String regex) { - return new StringMatchesFilter(regex, TEXT_GETTER); - } - - private String mText; - - private TextFilter(String text) { - mText = text; - } - - - @Override - public List filter(UiObject node) { - return node.findByText(mText); - } -} diff --git a/automator/src/main/java/com/stardust/automator/filter/TextFilter.kt b/automator/src/main/java/com/stardust/automator/filter/TextFilter.kt new file mode 100644 index 00000000..3d17f4f4 --- /dev/null +++ b/automator/src/main/java/com/stardust/automator/filter/TextFilter.kt @@ -0,0 +1,49 @@ +package com.stardust.automator.filter + +import com.stardust.automator.UiObject + +/** + * Created by Stardust on 2017/3/9. + */ + +class TextFilter private constructor(private val mText: String) : ListFilter.Default() { + + + override fun filter(node: UiObject): List { + return node.findByText(mText) + } + + companion object { + + private val TEXT_GETTER = object : KeyGetter { + override fun getKey(nodeInfo: UiObject): String? { + val charSequence = nodeInfo.text + return charSequence?.toString() + } + + override fun toString(): String { + return "text" + } + } + + fun equals(text: String): ListFilter { + return StringEqualsFilter(text, TEXT_GETTER) + } + + fun contains(str: String): ListFilter { + return StringContainsFilter(str, TEXT_GETTER) + } + + fun startsWith(prefix: String): ListFilter { + return StringStartsWithFilter(prefix, TEXT_GETTER) + } + + fun endsWith(suffix: String): ListFilter { + return StringEndsWithFilter(suffix, TEXT_GETTER) + } + + fun matches(regex: String): ListFilter { + return StringMatchesFilter(regex, TEXT_GETTER) + } + } +} diff --git a/automator/src/main/java/com/stardust/automator/simple_action/Able.java b/automator/src/main/java/com/stardust/automator/simple_action/Able.java deleted file mode 100644 index 32733e39..00000000 --- a/automator/src/main/java/com/stardust/automator/simple_action/Able.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.stardust.automator.simple_action; - -import android.util.SparseArray; -import android.view.accessibility.AccessibilityNodeInfo; - -import com.stardust.automator.UiObject; -import com.stardust.util.SparseArrayEntries; - -/** - * Created by Stardust on 2017/1/27. - */ - -public interface Able { - - SparseArray ABLE_MAP = new SparseArrayEntries() - .entry(AccessibilityNodeInfo.ACTION_CLICK, new Able() { - @Override - public boolean isAble(UiObject nodeInfo) { - return nodeInfo.isClickable(); - } - }) - .entry(AccessibilityNodeInfo.ACTION_LONG_CLICK, new Able() { - @Override - public boolean isAble(UiObject nodeInfo) { - return nodeInfo.isLongClickable(); - } - }) - .entry(AccessibilityNodeInfo.ACTION_FOCUS, new Able() { - @Override - public boolean isAble(UiObject nodeInfo) { - return nodeInfo.isFocusable(); - } - }) - .entry(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD, new Able() { - @Override - public boolean isAble(UiObject nodeInfo) { - return nodeInfo.isScrollable(); - } - }) - .entry(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD, new Able() { - @Override - public boolean isAble(UiObject nodeInfo) { - return nodeInfo.isScrollable(); - } - }) - .sparseArray(); - - boolean isAble(UiObject node); - -} diff --git a/automator/src/main/java/com/stardust/automator/simple_action/Able.kt b/automator/src/main/java/com/stardust/automator/simple_action/Able.kt new file mode 100644 index 00000000..345a4523 --- /dev/null +++ b/automator/src/main/java/com/stardust/automator/simple_action/Able.kt @@ -0,0 +1,46 @@ +package com.stardust.automator.simple_action + +import android.view.accessibility.AccessibilityNodeInfo +import com.stardust.automator.UiObject +import com.stardust.util.SparseArrayEntries + +/** + * Created by Stardust on 2017/1/27. + */ + +interface Able { + + fun isAble(node: UiObject): Boolean + + companion object { + + val ABLE_MAP = SparseArrayEntries() + .entry(AccessibilityNodeInfo.ACTION_CLICK, object : Able { + override fun isAble(nodeInfo: UiObject): Boolean { + return nodeInfo.isClickable + } + }) + .entry(AccessibilityNodeInfo.ACTION_LONG_CLICK, object : Able { + override fun isAble(nodeInfo: UiObject): Boolean { + return nodeInfo.isLongClickable + } + }) + .entry(AccessibilityNodeInfo.ACTION_FOCUS, object : Able { + override fun isAble(nodeInfo: UiObject): Boolean { + return nodeInfo.isFocusable + } + }) + .entry(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD, object : Able { + override fun isAble(nodeInfo: UiObject): Boolean { + return nodeInfo.isScrollable + } + }) + .entry(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD, object : Able { + override fun isAble(nodeInfo: UiObject): Boolean { + return nodeInfo.isScrollable + } + }) + .sparseArray() + } + +} diff --git a/automator/src/main/java/com/stardust/automator/simple_action/ActionFactory.java b/automator/src/main/java/com/stardust/automator/simple_action/ActionFactory.java deleted file mode 100644 index e18fe2e9..00000000 --- a/automator/src/main/java/com/stardust/automator/simple_action/ActionFactory.java +++ /dev/null @@ -1,72 +0,0 @@ -package com.stardust.automator.simple_action; - -import android.graphics.Rect; -import android.os.Build; -import android.os.Bundle; -import android.support.annotation.RequiresApi; -import android.view.accessibility.AccessibilityNodeInfo; - -import com.stardust.automator.UiObject; -import com.stardust.util.MapBuilder; - -import java.util.Map; - -/** - * Created by Stardust on 2017/1/27. - */ - -public class ActionFactory { - - private static Map searchUpAction = new MapBuilder() - .put(AccessibilityNodeInfo.ACTION_CLICK, null) - .put(AccessibilityNodeInfo.ACTION_LONG_CLICK, null) - .put(AccessibilityNodeInfo.ACTION_SELECT, null) - .put(AccessibilityNodeInfo.ACTION_FOCUS, null) - .put(AccessibilityNodeInfo.ACTION_SELECT, null) - .put(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD, null) - .put(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD, null) - .build(); - - public static SimpleAction createActionWithTextFilter(int action, String text, int index) { - if (searchUpAction.containsKey(action)) - return new SearchUpTargetAction(action, new FilterAction.TextFilter(text, index)); - else - return new DepthFirstSearchTargetAction(action, new FilterAction.TextFilter(text, index)); - } - - public static SimpleAction createActionWithBoundsFilter(int action, Rect rect) { - if (searchUpAction.containsKey(action)) - return new SearchUpTargetAction(action, new FilterAction.BoundsFilter(rect)); - else - return new DepthFirstSearchTargetAction(action, new FilterAction.BoundsFilter(rect)); - } - - @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) - public static SimpleAction createActionWithEditableFilter(final int action, int index, final String text) { - return new SearchTargetAction(action, new FilterAction.EditableFilter(index)) { - - @Override - protected boolean performAction(UiObject node) { - Bundle args = new Bundle(); - if (action == AccessibilityNodeInfo.ACTION_SET_TEXT) { - args.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, text); - } else { - args.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, node.text() + text); - } - return node.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, args); - } - }; - } - - public static SimpleAction createScrollMaxAction(int action) { - return new ScrollMaxAction(action); - } - - public static SimpleAction createScrollAction(int action, int i) { - return new ScrollAction(action, i); - } - - public static SimpleAction createActionWithIdFilter(int action, String id) { - return new FilterAction.SimpleFilterAction(action, new FilterAction.IdFilter(id)); - } -} diff --git a/automator/src/main/java/com/stardust/automator/simple_action/ActionFactory.kt b/automator/src/main/java/com/stardust/automator/simple_action/ActionFactory.kt new file mode 100644 index 00000000..aa2fc185 --- /dev/null +++ b/automator/src/main/java/com/stardust/automator/simple_action/ActionFactory.kt @@ -0,0 +1,69 @@ +package com.stardust.automator.simple_action + +import android.graphics.Rect +import android.os.Build +import android.os.Bundle +import android.support.annotation.RequiresApi +import android.view.accessibility.AccessibilityNodeInfo + +import com.stardust.automator.UiObject +import com.stardust.util.MapBuilder + +/** + * Created by Stardust on 2017/1/27. + */ + +object ActionFactory { + + private val searchUpAction = MapBuilder() + .put(AccessibilityNodeInfo.ACTION_CLICK, null) + .put(AccessibilityNodeInfo.ACTION_LONG_CLICK, null) + .put(AccessibilityNodeInfo.ACTION_SELECT, null) + .put(AccessibilityNodeInfo.ACTION_FOCUS, null) + .put(AccessibilityNodeInfo.ACTION_SELECT, null) + .put(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD, null) + .put(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD, null) + .build() + + fun createActionWithTextFilter(action: Int, text: String, index: Int): SimpleAction { + return if (searchUpAction.containsKey(action)) + SearchUpTargetAction(action, FilterAction.TextFilter(text, index)) + else + DepthFirstSearchTargetAction(action, FilterAction.TextFilter(text, index)) + } + + fun createActionWithBoundsFilter(action: Int, rect: Rect): SimpleAction { + return if (searchUpAction.containsKey(action)) + SearchUpTargetAction(action, FilterAction.BoundsFilter(rect)) + else + DepthFirstSearchTargetAction(action, FilterAction.BoundsFilter(rect)) + } + + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + fun createActionWithEditableFilter(action: Int, index: Int, text: String): SimpleAction { + return object : SearchTargetAction(action, FilterAction.EditableFilter(index)) { + + override fun performAction(node: UiObject): Boolean { + val args = Bundle() + if (action == AccessibilityNodeInfo.ACTION_SET_TEXT) { + args.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, text) + } else { + args.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, node.text() + text) + } + return node.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, args) + } + } + } + + fun createScrollMaxAction(action: Int): SimpleAction { + return ScrollMaxAction(action) + } + + fun createScrollAction(action: Int, i: Int): SimpleAction { + return ScrollAction(action, i) + } + + fun createActionWithIdFilter(action: Int, id: String): SimpleAction { + return FilterAction.SimpleFilterAction(action, FilterAction.IdFilter(id)) + } +} diff --git a/automator/src/main/java/com/stardust/automator/simple_action/ActionTarget.java b/automator/src/main/java/com/stardust/automator/simple_action/ActionTarget.java deleted file mode 100644 index fd3388d4..00000000 --- a/automator/src/main/java/com/stardust/automator/simple_action/ActionTarget.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.stardust.automator.simple_action; - -import android.graphics.Rect; -import android.os.Build; -import android.support.annotation.RequiresApi; - -/** - * Created by Stardust on 2017/1/27. - */ - -public interface ActionTarget { - - SimpleAction createAction(int action, Object... params); - - class TextActionTarget implements ActionTarget { - - String mText; - int mIndex; - - public TextActionTarget(String text, int i) { - mText = text; - mIndex = i; - } - - @Override - public SimpleAction createAction(int action, Object... params) { - return ActionFactory.createActionWithTextFilter(action, mText, mIndex); - } - } - - class BoundsActionTarget implements ActionTarget { - - Rect mBoundsInRect; - - public BoundsActionTarget(Rect rect) { - mBoundsInRect = rect; - } - - @Override - public SimpleAction createAction(int action, Object... params) { - return ActionFactory.createActionWithBoundsFilter(action, mBoundsInRect); - } - } - - @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) - class EditableActionTarget implements ActionTarget { - private int mIndex; - - public EditableActionTarget(int index) { - mIndex = index; - } - - @Override - public SimpleAction createAction(int action, Object... params) { - return ActionFactory.createActionWithEditableFilter(action, mIndex, params[0].toString()); - } - } - - class IdActionTarget implements ActionTarget { - private String mId; - - public IdActionTarget(String id) { - mId = id; - } - - @Override - public SimpleAction createAction(int action, Object... params) { - return ActionFactory.createActionWithIdFilter(action, mId); - } - } -} diff --git a/automator/src/main/java/com/stardust/automator/simple_action/ActionTarget.kt b/automator/src/main/java/com/stardust/automator/simple_action/ActionTarget.kt new file mode 100644 index 00000000..698a438d --- /dev/null +++ b/automator/src/main/java/com/stardust/automator/simple_action/ActionTarget.kt @@ -0,0 +1,43 @@ +package com.stardust.automator.simple_action + +import android.graphics.Rect +import android.os.Build +import android.support.annotation.RequiresApi + +/** + * Created by Stardust on 2017/1/27. + */ + +interface ActionTarget { + + fun createAction(action: Int, vararg params: Any): SimpleAction + + class TextActionTarget(private var mText: String, internal var mIndex: Int) : ActionTarget { + + override fun createAction(action: Int, vararg params: Any): SimpleAction { + return ActionFactory.createActionWithTextFilter(action, mText, mIndex) + } + } + + class BoundsActionTarget(private var mBoundsInRect: Rect) : ActionTarget { + + override fun createAction(action: Int, vararg params: Any): SimpleAction { + return ActionFactory.createActionWithBoundsFilter(action, mBoundsInRect) + } + } + + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + class EditableActionTarget(private val mIndex: Int) : ActionTarget { + + override fun createAction(action: Int, vararg params: Any): SimpleAction { + return ActionFactory.createActionWithEditableFilter(action, mIndex, params[0].toString()) + } + } + + class IdActionTarget(private val mId: String) : ActionTarget { + + override fun createAction(action: Int, vararg params: Any): SimpleAction { + return ActionFactory.createActionWithIdFilter(action, mId) + } + } +} diff --git a/automator/src/main/java/com/stardust/automator/simple_action/DepthFirstSearchTargetAction.java b/automator/src/main/java/com/stardust/automator/simple_action/DepthFirstSearchTargetAction.java deleted file mode 100644 index 7268040f..00000000 --- a/automator/src/main/java/com/stardust/automator/simple_action/DepthFirstSearchTargetAction.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.stardust.automator.simple_action; - -import com.stardust.automator.UiObject; - -/** - * Created by Stardust on 2017/1/27. - */ - -public class DepthFirstSearchTargetAction extends SearchTargetAction { - - - private Able mAble; - - public DepthFirstSearchTargetAction(int action, Filter filter) { - super(action, filter); - mAble = Able.ABLE_MAP.get(action); - } - - - @Override - public UiObject searchTarget(UiObject n) { - if (n == null) - return null; - if (mAble.isAble(n)) - return n; - for (int i = 0; i < n.getChildCount(); i++) { - UiObject child = n.child(i); - if (child == null) - continue; - UiObject node = searchTarget(child); - if (node != null) - return node; - } - return null; - } - - -} diff --git a/automator/src/main/java/com/stardust/automator/simple_action/DepthFirstSearchTargetAction.kt b/automator/src/main/java/com/stardust/automator/simple_action/DepthFirstSearchTargetAction.kt new file mode 100644 index 00000000..1c06839a --- /dev/null +++ b/automator/src/main/java/com/stardust/automator/simple_action/DepthFirstSearchTargetAction.kt @@ -0,0 +1,28 @@ +package com.stardust.automator.simple_action + +import com.stardust.automator.UiObject + +/** + * Created by Stardust on 2017/1/27. + */ + +class DepthFirstSearchTargetAction(action: Int, filter: FilterAction.Filter) : SearchTargetAction(action, filter) { + + private val mAble: Able = Able.ABLE_MAP.get(action) + + override fun searchTarget(node: UiObject?): UiObject? { + if (node == null) + return null + if (mAble.isAble(node)) + return node + for (i in 0 until node.childCount) { + val child = node.child(i) ?: continue + val targetNode = searchTarget(child) + if (targetNode != null) + return targetNode + } + return null + } + + +} diff --git a/automator/src/main/java/com/stardust/automator/simple_action/FilterAction.java b/automator/src/main/java/com/stardust/automator/simple_action/FilterAction.java deleted file mode 100644 index 7cc0c7d2..00000000 --- a/automator/src/main/java/com/stardust/automator/simple_action/FilterAction.java +++ /dev/null @@ -1,205 +0,0 @@ -package com.stardust.automator.simple_action; - -import android.graphics.Rect; - -import com.stardust.automator.UiObject; -import com.stardust.automator.filter.BoundsFilter; -import com.stardust.view.accessibility.AccessibilityNodeInfoHelper; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; - -/** - * Created by Stardust on 2017/1/27. - */ - -public abstract class FilterAction extends SimpleAction { - - - public interface Filter { - - List filter(UiObject root); - } - - public static class TextFilter implements Filter { - - String mText; - int mIndex; - - public TextFilter(String text, int index) { - mText = text; - mIndex = index; - } - - @Override - public List filter(UiObject root) { - List list = root.findByText(mText); - if (mIndex == -1) - return list; - if (mIndex >= list.size()) - return Collections.emptyList(); - return Collections.singletonList(list.get(mIndex)); - } - - @Override - public String toString() { - return "TextFilter{" + - "mText='" + mText + '\'' + - ", mIndex=" + mIndex + - '}'; - } - } - - public static class BoundsFilter implements Filter { - - Rect mBoundsInScreen; - - public BoundsFilter(Rect boundsInScreen) { - mBoundsInScreen = boundsInScreen; - } - - @Override - public List filter(UiObject root) { - List list = new ArrayList<>(); - findAccessibilityNodeInfosByBounds(root, list); - return list; - } - - private void findAccessibilityNodeInfosByBounds(UiObject root, List list) { - if (root == null) - return; - Rect rect = new Rect(); - root.getBoundsInScreen(rect); - if (rect.equals(mBoundsInScreen)) { - list.add(root); - } - int oldSize = list.size(); - for (int i = 0; i < root.getChildCount(); i++) { - UiObject child = root.child(i); - if (child == null) - continue; - findAccessibilityNodeInfosByBounds(child, list); - } - if (oldSize == list.size() && rect.contains(mBoundsInScreen)) { - list.add(root); - } - } - - @Override - public String toString() { - return "BoundsFilter{" + - "mBoundsInScreen=" + mBoundsInScreen + - '}'; - } - } - - public static class EditableFilter implements Filter { - - private int mIndex; - - public EditableFilter(int index) { - mIndex = index; - } - - @Override - public List filter(UiObject root) { - List editableList = findEditable(root); - if (mIndex == -1) - return editableList; - if (mIndex >= editableList.size()) - return Collections.emptyList(); - return Collections.singletonList(editableList.get(mIndex)); - } - - public static List findEditable(UiObject root) { - if (root == null) { - return Collections.emptyList(); - } - if (root.isEditable()) { - return Collections.singletonList(root); - } - List list = new LinkedList<>(); - for (int i = 0; i < root.getChildCount(); i++) { - list.addAll(findEditable(root.child(i))); - } - return list; - } - - @Override - public String toString() { - return "EditableFilter{" + - "mIndex=" + mIndex + - '}'; - } - } - - public static class IdFilter implements Filter { - - private final String mId; - - public IdFilter(String id) { - this.mId = id; - } - - @Override - public List filter(UiObject root) { - return root.findByViewId(mId); - } - - @Override - public String toString() { - return "IdFilter{" + - "mId='" + mId + '\'' + - '}'; - } - } - - - private Filter mFilter; - - public FilterAction(Filter filter) { - mFilter = filter; - } - - @Override - public boolean perform(UiObject root) { - if (root == null) - return false; - List list = mFilter.filter(root); - return perform(list); - } - - public abstract boolean perform(List nodes); - - public static class SimpleFilterAction extends FilterAction { - - private int mAction; - - public SimpleFilterAction(int action, Filter filter) { - super(filter); - mAction = action; - } - - @Override - public boolean perform(List nodes) { - if (nodes == null || nodes.isEmpty()) - return false; - boolean succeed = true; - for (UiObject nodeInfo : nodes) { - if (!nodeInfo.performAction(mAction)) { - succeed = false; - } - } - return succeed; - } - } - - @Override - public String toString() { - return "FilterAction{" + - "mFilter=" + mFilter + - '}'; - } -} diff --git a/automator/src/main/java/com/stardust/automator/simple_action/FilterAction.kt b/automator/src/main/java/com/stardust/automator/simple_action/FilterAction.kt new file mode 100644 index 00000000..04d17c00 --- /dev/null +++ b/automator/src/main/java/com/stardust/automator/simple_action/FilterAction.kt @@ -0,0 +1,142 @@ +package com.stardust.automator.simple_action + +import android.graphics.Rect +import com.stardust.automator.UiObject +import java.util.* + +/** + * Created by Stardust on 2017/1/27. + */ + +abstract class FilterAction(private val mFilter: Filter) : SimpleAction() { + + abstract fun perform(nodes: List): Boolean + + interface Filter { + + fun filter(root: UiObject): List + } + + class TextFilter(private var mText: String, internal var mIndex: Int) : Filter { + + override fun filter(root: UiObject): List { + val list = root.findByText(mText) + if (mIndex == -1) + return list + return if (mIndex >= list.size) emptyList() else listOf(list[mIndex]) + } + + override fun toString(): String { + return "TextFilter{" + + "mText='" + mText + '\''.toString() + + ", mIndex=" + mIndex + + '}'.toString() + } + } + + class BoundsFilter(private var mBoundsInScreen: Rect) : Filter { + + override fun filter(root: UiObject): List { + val list = ArrayList() + findAccessibilityNodeInfosByBounds(root, list) + return list + } + + private fun findAccessibilityNodeInfosByBounds(root: UiObject?, list: MutableList) { + if (root == null) + return + val rect = Rect() + root.getBoundsInScreen(rect) + if (rect == mBoundsInScreen) { + list.add(root) + } + val oldSize = list.size + for (i in 0 until root.childCount) { + val child = root.child(i) ?: continue + findAccessibilityNodeInfosByBounds(child, list) + } + if (oldSize == list.size && rect.contains(mBoundsInScreen)) { + list.add(root) + } + } + + override fun toString(): String { + return "BoundsFilter{" + + "mBoundsInScreen=" + mBoundsInScreen + + '}'.toString() + } + } + + class EditableFilter(private val mIndex: Int) : Filter { + + override fun filter(root: UiObject): List { + val editableList = findEditable(root) + if (mIndex == -1) + return editableList + return if (mIndex >= editableList.size) emptyList() else listOf(editableList[mIndex]) + } + + override fun toString(): String { + return "EditableFilter{" + + "mIndex=" + mIndex + + '}'.toString() + } + + companion object { + + fun findEditable(root: UiObject?): List { + if (root == null) { + return emptyList() + } + if (root.isEditable) { + return listOf(root) + } + val list = LinkedList() + for (i in 0 until root.childCount) { + list.addAll(findEditable(root.child(i))) + } + return list + } + } + } + + class IdFilter(private val mId: String) : Filter { + + override fun filter(root: UiObject): List { + return root.findByViewId(mId) + } + + override fun toString(): String { + return "IdFilter{" + + "mId='" + mId + '\''.toString() + + '}'.toString() + } + } + + override fun perform(root: UiObject): Boolean { + val list = mFilter.filter(root) + return perform(list) + } + + + class SimpleFilterAction(private val mAction: Int, filter: Filter) : FilterAction(filter) { + + override fun perform(nodes: List): Boolean { + if (nodes.isEmpty()) + return false + var succeed = true + for (nodeInfo in nodes) { + if (!nodeInfo.performAction(mAction)) { + succeed = false + } + } + return succeed + } + } + + override fun toString(): String { + return "FilterAction{" + + "mFilter=" + mFilter + + '}'.toString() + } +} diff --git a/automator/src/main/java/com/stardust/automator/simple_action/ScrollAction.java b/automator/src/main/java/com/stardust/automator/simple_action/ScrollAction.java deleted file mode 100644 index 96157371..00000000 --- a/automator/src/main/java/com/stardust/automator/simple_action/ScrollAction.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.stardust.automator.simple_action; - -import com.stardust.automator.UiObject; - -import java.util.ArrayList; -import java.util.List; - -/** - * Created by Stardust on 2017/2/12. - */ -public class ScrollAction extends SimpleAction { - - private int mIndex, mAction; - - public ScrollAction(int action, int i) { - mAction = action; - mIndex = i; - } - - @Override - public boolean perform(UiObject root) { - List scrollableNodes = findScrollableNodes(root); - boolean result = mIndex < scrollableNodes.size() && scrollableNodes.get(mIndex).performAction(mAction); - recycle(scrollableNodes, root); - return result; - } - - private void recycle(List list, UiObject root) { - for (UiObject nodeInfo : list) { - if (nodeInfo != root) - nodeInfo.recycle(); - } - } - - private List findScrollableNodes(UiObject root) { - List list = new ArrayList<>(); - if (root != null) { - findScrollableNodes(root, list); - if (root.isScrollable()) { - list.add(root); - } - } - return list; - } - - private static void findScrollableNodes(UiObject node, List list) { - if (node == null) { - return; - } - for (int i = 0; i < node.getChildCount(); i++) { - UiObject child = node.child(i); - if (child == null) - continue; - findScrollableNodes(child, list); - if (child.isScrollable()) { - list.add(child); - } else { - child.recycle(); - } - } - } -} diff --git a/automator/src/main/java/com/stardust/automator/simple_action/ScrollAction.kt b/automator/src/main/java/com/stardust/automator/simple_action/ScrollAction.kt new file mode 100644 index 00000000..57166d3d --- /dev/null +++ b/automator/src/main/java/com/stardust/automator/simple_action/ScrollAction.kt @@ -0,0 +1,51 @@ +package com.stardust.automator.simple_action + +import com.stardust.automator.UiObject + +import java.util.ArrayList + +/** + * Created by Stardust on 2017/2/12. + */ +class ScrollAction(private val mAction: Int, private val mIndex: Int) : SimpleAction() { + + override fun perform(root: UiObject): Boolean { + val scrollableNodes = findScrollableNodes(root) + val result = mIndex < scrollableNodes.size && scrollableNodes[mIndex].performAction(mAction) + recycle(scrollableNodes, root) + return result + } + + private fun recycle(list: List, root: UiObject) { + for (nodeInfo in list) { + if (nodeInfo !== root) + nodeInfo.recycle() + } + } + + private fun findScrollableNodes(root: UiObject?): List { + val list = ArrayList() + if (root != null) { + findScrollableNodes(root, list) + if (root.isScrollable) { + list.add(root) + } + } + return list + } + + private fun findScrollableNodes(node: UiObject?, list: MutableList) { + if (node == null) { + return + } + for (i in 0 until node.childCount) { + val child = node.child(i) ?: continue + findScrollableNodes(child, list) + if (child.isScrollable) { + list.add(child) + } else { + child.recycle() + } + } + } +} diff --git a/automator/src/main/java/com/stardust/automator/simple_action/ScrollMaxAction.java b/automator/src/main/java/com/stardust/automator/simple_action/ScrollMaxAction.java deleted file mode 100644 index 6c2eb2f4..00000000 --- a/automator/src/main/java/com/stardust/automator/simple_action/ScrollMaxAction.java +++ /dev/null @@ -1,78 +0,0 @@ -package com.stardust.automator.simple_action; - -import android.graphics.Rect; -import android.util.Log; - -import com.stardust.automator.UiObject; - -import java.util.HashSet; -import java.util.Set; - -/** - * Created by Stardust on 2017/1/27. - */ - -public class ScrollMaxAction extends SimpleAction { - - private static final String TAG = ScrollMaxAction.class.getSimpleName(); - private int mScrollAction; - private UiObject mMaxScrollableNode; - private UiObject mRootNode; - private Set mRecycledMaxUiObjects = new HashSet<>(); - - public ScrollMaxAction(int scrollAction) { - mScrollAction = scrollAction; - } - - @Override - public boolean perform(UiObject rootNodeInfo) { - reset(); - mRootNode = rootNodeInfo; - findMaxScrollableNodeInfo(rootNodeInfo); - boolean result = mMaxScrollableNode != null && mMaxScrollableNode.performAction(mScrollAction); - reset(); - return result; - } - - private void reset() { - if (mMaxScrollableNode != null && mMaxScrollableNode != mRootNode) { - mMaxScrollableNode.recycle(); - } - mMaxScrollableNode = mRootNode = null; - mRecycledMaxUiObjects.clear(); - } - - private void findMaxScrollableNodeInfo(UiObject nodeInfo) { - if (nodeInfo == null) - return; - if (nodeInfo.isScrollable()) { - if (mMaxScrollableNode == null) { - mMaxScrollableNode = nodeInfo; - } else if (getAreaInScreen(mMaxScrollableNode) < getAreaInScreen(nodeInfo)) { - if (mMaxScrollableNode != mRootNode) { - mRecycledMaxUiObjects.add(mMaxScrollableNode); - mMaxScrollableNode.recycle(); - } - mMaxScrollableNode = nodeInfo; - } - } - for (int i = 0; i < nodeInfo.getChildCount(); i++) { - UiObject child = nodeInfo.child(i); - if (child != null) { - findMaxScrollableNodeInfo(child); - if (mMaxScrollableNode != child && !mRecycledMaxUiObjects.contains(child)) { - child.recycle(); - } - } - } - } - - private long getAreaInScreen(UiObject nodeInfo) { - Rect rect = new Rect(); - nodeInfo.getBoundsInScreen(rect); - long area = ((long) rect.width()) * rect.height(); - Log.v(TAG, "area=" + area); - return area; - } - -} diff --git a/automator/src/main/java/com/stardust/automator/simple_action/ScrollMaxAction.kt b/automator/src/main/java/com/stardust/automator/simple_action/ScrollMaxAction.kt new file mode 100644 index 00000000..2983a204 --- /dev/null +++ b/automator/src/main/java/com/stardust/automator/simple_action/ScrollMaxAction.kt @@ -0,0 +1,79 @@ +package com.stardust.automator.simple_action + +import android.graphics.Rect +import android.util.Log + +import com.stardust.automator.UiObject + +import java.util.HashSet + +/** + * Created by Stardust on 2017/1/27. + */ + +class ScrollMaxAction(private val mScrollAction: Int) : SimpleAction() { + private var mMaxScrollableNode: UiObject? = null + private var mRootNode: UiObject? = null + private val mRecycledMaxUiObjects = HashSet() + + override fun perform(root: UiObject): Boolean { + reset() + mRootNode = root + findMaxScrollableNodeInfo(root) + val result = mMaxScrollableNode != null && mMaxScrollableNode!!.performAction(mScrollAction) + reset() + return result + } + + private fun reset() { + mMaxScrollableNode?.let { + if(it != mRootNode){ + it.recycle() + } + } + mRootNode = null + mMaxScrollableNode = mRootNode + mRecycledMaxUiObjects.clear() + } + + private fun findMaxScrollableNodeInfo(nodeInfo: UiObject?) { + if (nodeInfo == null) + return + + if (nodeInfo.isScrollable) { + val maxScrollableNode = mMaxScrollableNode + if (maxScrollableNode == null) { + mMaxScrollableNode = nodeInfo + } else if (getAreaInScreen(maxScrollableNode) < getAreaInScreen(nodeInfo)) { + if (maxScrollableNode !== mRootNode) { + mRecycledMaxUiObjects.add(maxScrollableNode) + maxScrollableNode.recycle() + } + mMaxScrollableNode = nodeInfo + } + } + for (i in 0 until nodeInfo.childCount) { + val child = nodeInfo.child(i) + if (child != null) { + findMaxScrollableNodeInfo(child) + if (mMaxScrollableNode !== child && !mRecycledMaxUiObjects.contains(child)) { + child.recycle() + } + } + } + } + + private fun getAreaInScreen(nodeInfo: UiObject): Long { + val rect = Rect() + nodeInfo.getBoundsInScreen(rect) + val area = rect.width().toLong() * rect.height() + Log.v(TAG, "area=$area") + return area + } + + companion object { + + private val TAG = ScrollMaxAction::class.java.simpleName + } + +} diff --git a/automator/src/main/java/com/stardust/automator/simple_action/SearchTargetAction.java b/automator/src/main/java/com/stardust/automator/simple_action/SearchTargetAction.java deleted file mode 100644 index eb4aa053..00000000 --- a/automator/src/main/java/com/stardust/automator/simple_action/SearchTargetAction.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.stardust.automator.simple_action; - -import android.graphics.BitmapFactory; - -import com.stardust.automator.UiObject; - -import java.util.List; - -/** - * Created by Stardust on 2017/1/27. - */ - -public abstract class SearchTargetAction extends FilterAction { - - private int mAction; - - public SearchTargetAction(int action, Filter filter) { - super(filter); - mAction = action; - } - - - @Override - public boolean perform(List nodes) { - boolean performed = false; - for (UiObject node : nodes) { - node = searchTarget(node); - if (node != null && performAction(node)) { - performed = true; - } - } - return performed; - } - - protected boolean performAction(UiObject node) { - return node.performAction(mAction); - } - - public int getAction() { - return mAction; - } - - public UiObject searchTarget(UiObject node) { - return node; - } - - @Override - public String toString() { - return "SearchTargetAction{" + - "mAction=" + mAction + ", " + - super.toString() + - "}"; - } -} diff --git a/automator/src/main/java/com/stardust/automator/simple_action/SearchTargetAction.kt b/automator/src/main/java/com/stardust/automator/simple_action/SearchTargetAction.kt new file mode 100644 index 00000000..7480664e --- /dev/null +++ b/automator/src/main/java/com/stardust/automator/simple_action/SearchTargetAction.kt @@ -0,0 +1,38 @@ +package com.stardust.automator.simple_action + +import android.graphics.BitmapFactory + +import com.stardust.automator.UiObject + +/** + * Created by Stardust on 2017/1/27. + */ + +abstract class SearchTargetAction(val action: Int, filter: FilterAction.Filter) : FilterAction(filter) { + + override fun perform(nodes: List): Boolean { + var performed = false + for (node in nodes) { + val targetNode = searchTarget(node) + if (targetNode != null && performAction(targetNode)) { + performed = true + } + } + return performed + } + + protected open fun performAction(node: UiObject): Boolean { + return node.performAction(action) + } + + open fun searchTarget(node: UiObject?): UiObject? { + return node + } + + override fun toString(): String { + return "SearchTargetAction{" + + "mAction=" + action + ", " + + super.toString() + + "}" + } +} diff --git a/automator/src/main/java/com/stardust/automator/simple_action/SearchUpTargetAction.java b/automator/src/main/java/com/stardust/automator/simple_action/SearchUpTargetAction.java deleted file mode 100644 index c5e1ba89..00000000 --- a/automator/src/main/java/com/stardust/automator/simple_action/SearchUpTargetAction.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.stardust.automator.simple_action; - - -import com.stardust.automator.UiObject; - -/** - * Created by Stardust on 2017/1/27. - */ - -public class SearchUpTargetAction extends SearchTargetAction { - - private static final String TAG = SearchUpTargetAction.class.getSimpleName(); - private static final int LOOP_MAX = 20; - private Able mAble; - - public SearchUpTargetAction(int action, Filter filter) { - super(action, filter); - mAble = Able.ABLE_MAP.get(action); - } - - @Override - public UiObject searchTarget(UiObject n) { - UiObject node = n; - int i = 0; - while (node != null && !mAble.isAble(node)) { - i++; - if (i > LOOP_MAX) { - return null; - } - node = node.parent(); - } - return node; - } - - @Override - public String toString() { - return "SearchUpTargetAction{" + - "mAble=" + mAble + ", " + - super.toString() + - '}'; - } -} diff --git a/automator/src/main/java/com/stardust/automator/simple_action/SearchUpTargetAction.kt b/automator/src/main/java/com/stardust/automator/simple_action/SearchUpTargetAction.kt new file mode 100644 index 00000000..b02f091e --- /dev/null +++ b/automator/src/main/java/com/stardust/automator/simple_action/SearchUpTargetAction.kt @@ -0,0 +1,38 @@ +package com.stardust.automator.simple_action + + +import com.stardust.automator.UiObject + +/** + * Created by Stardust on 2017/1/27. + */ + +class SearchUpTargetAction(action: Int, filter: FilterAction.Filter) : SearchTargetAction(action, filter) { + private val mAble: Able = Able.ABLE_MAP.get(action) + + override fun searchTarget(n: UiObject?): UiObject? { + var node = n + var i = 0 + while (node != null && !mAble.isAble(node)) { + i++ + if (i > LOOP_MAX) { + return null + } + node = node.parent() + } + return node + } + + override fun toString(): String { + return "SearchUpTargetAction{" + + "mAble=" + mAble + ", " + + super.toString() + + '}'.toString() + } + + companion object { + + private val TAG = SearchUpTargetAction::class.java!!.getSimpleName() + private val LOOP_MAX = 20 + } +} diff --git a/automator/src/main/java/com/stardust/automator/simple_action/SimpleAction.java b/automator/src/main/java/com/stardust/automator/simple_action/SimpleAction.java deleted file mode 100644 index b660ec16..00000000 --- a/automator/src/main/java/com/stardust/automator/simple_action/SimpleAction.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.stardust.automator.simple_action; - -import com.stardust.automator.UiObject; - -/** - * Created by Stardust on 2017/1/27. - */ - -public abstract class SimpleAction { - - private volatile boolean mValid = true; - private volatile boolean mResult = false; - - public abstract boolean perform(UiObject root); - - public boolean getResult() { - return mResult; - } - - public void setResult(boolean result) { - mResult = result; - } - - public void setValid(boolean valid) { - mValid = valid; - } - - public boolean isValid() { - return mValid; - } - -} diff --git a/automator/src/main/java/com/stardust/automator/simple_action/SimpleAction.kt b/automator/src/main/java/com/stardust/automator/simple_action/SimpleAction.kt new file mode 100644 index 00000000..f7492c55 --- /dev/null +++ b/automator/src/main/java/com/stardust/automator/simple_action/SimpleAction.kt @@ -0,0 +1,18 @@ +package com.stardust.automator.simple_action + +import com.stardust.automator.UiObject + +/** + * Created by Stardust on 2017/1/27. + */ + +abstract class SimpleAction { + + @Volatile + var isValid = true + @Volatile + var result = false + + abstract fun perform(root: UiObject): Boolean + +} diff --git a/automator/src/main/java/com/stardust/automator/test/TestUiObject.java b/automator/src/main/java/com/stardust/automator/test/TestUiObject.java deleted file mode 100644 index 9621d144..00000000 --- a/automator/src/main/java/com/stardust/automator/test/TestUiObject.java +++ /dev/null @@ -1,100 +0,0 @@ -package com.stardust.automator.test; - -import android.graphics.Rect; -import android.os.Bundle; -import android.util.Log; - -import com.stardust.automator.UiObject; - -import java.util.Arrays; -import java.util.Random; - -/** - * Created by Stardust on 2017/5/5. - */ - -public class TestUiObject extends UiObject { - - public static int count = 0; - public static int max = 0; - private static Random random = new Random(); - - private int mHashCode = random.nextInt(); - private boolean mRecycled = false; - private int mChildCount; - - public TestUiObject(int i) { - super(null); - count++; - max = Math.max(max, count); - mChildCount = i; - } - - - public TestUiObject() { - this(Math.max(0, random.nextInt(6) - 2)); - } - - @Override - public UiObject child(int i) { - return new TestUiObject(); - } - - @Override - public UiObject parent() { - return new TestUiObject(); - } - - @Override - public int getChildCount() { - return mChildCount; - } - - @Override - public boolean isScrollable() { - return random.nextInt(4) == 0; - } - - @Override - public boolean isClickable() { - return random.nextBoolean(); - } - - @Override - public void getBoundsInScreen(Rect outBounds) { - int left = random.nextInt(1080); - int top = random.nextInt(1920); - int right = random.nextInt(1080 - left) + left; - int bottom = random.nextInt(1920 - top) + top; - outBounds.set(left, top, right, bottom); - } - - @Override - public boolean performAction(int action, Bundle bundle) { - return random.nextBoolean(); - } - - @Override - public boolean performAction(int action) { - return random.nextBoolean(); - } - - @Override - public void recycle() { - if (mRecycled) { - throw new IllegalStateException(); - } - mRecycled = true; - count--; - } - - @Override - public String toString() { - return "UiObject@" + Integer.toHexString(hashCode()); - } - - @Override - public int hashCode() { - return mHashCode; - } -} diff --git a/automator/src/main/java/com/stardust/automator/test/TestUiObject.kt b/automator/src/main/java/com/stardust/automator/test/TestUiObject.kt new file mode 100644 index 00000000..1e37b809 --- /dev/null +++ b/automator/src/main/java/com/stardust/automator/test/TestUiObject.kt @@ -0,0 +1,85 @@ +package com.stardust.automator.test + +import android.graphics.Rect +import android.os.Bundle +import android.view.accessibility.AccessibilityNodeInfo +import com.stardust.automator.UiObject +import java.util.* + +/** + * Created by Stardust on 2017/5/5. + */ + +class TestUiObject @JvmOverloads constructor(private val mChildCount: Int = Math.max(0, random.nextInt(6) - 2)) : UiObject(null) { + + private val mHashCode = random.nextInt() + private var mRecycled = false + + init { + count++ + max = Math.max(max, count) + } + + override fun child(i: Int): UiObject? { + return TestUiObject() + } + + override fun parent(): UiObject? { + return TestUiObject() + } + + override fun getChildCount(): Int { + return mChildCount + } + + override fun isScrollable(): Boolean { + return random.nextInt(4) == 0 + } + + override fun isClickable(): Boolean { + return random.nextBoolean() + } + + override fun getBoundsInScreen(outBounds: Rect) { + val left = random.nextInt(1080) + val top = random.nextInt(1920) + val right = random.nextInt(1080 - left) + left + val bottom = random.nextInt(1920 - top) + top + outBounds.set(left, top, right, bottom) + } + + override fun performAction(action: Int, bundle: Bundle): Boolean { + return random.nextBoolean() + } + + override fun performAction(action: Int): Boolean { + return random.nextBoolean() + } + + override fun recycle() { + if (mRecycled) { + throw IllegalStateException() + } + mRecycled = true + count-- + } + + override fun toString(): String { + return "UiObject@" + Integer.toHexString(hashCode()) + } + + override fun hashCode(): Int { + return mHashCode + } + + override fun equals(other: Any?): Boolean { + return this === other + } + + companion object { + + var count = 0 + var max = 0 + private val random = Random() + } +} diff --git a/automator/src/main/java/com/stardust/notification/Notification.java b/automator/src/main/java/com/stardust/notification/Notification.java deleted file mode 100644 index 4a523d23..00000000 --- a/automator/src/main/java/com/stardust/notification/Notification.java +++ /dev/null @@ -1,104 +0,0 @@ -package com.stardust.notification; - -import android.app.PendingIntent; -import android.os.Build; -import android.os.Parcel; -import android.support.annotation.RequiresApi; - -/** - * Created by Stardust on 2017/10/30. - */ - -public class Notification extends android.app.Notification { - - private String mPackageName; - - private Notification(String packageName) { - mPackageName = packageName; - } - - public static Notification create(android.app.Notification n, String packageName) { - Notification notification = new Notification(packageName); - clone(n, notification); - return notification; - } - - public String getPackageName() { - return mPackageName; - } - - @RequiresApi(api = Build.VERSION_CODES.KITKAT) - public String getText() { - return extras.getString(EXTRA_TEXT); - } - - @RequiresApi(api = Build.VERSION_CODES.KITKAT) - public String getTitle() { - return extras.getString(EXTRA_TITLE); - } - - public void click() { - try { - this.contentIntent.send(); - } catch (PendingIntent.CanceledException e) { - throw new RuntimeException(e); - } - } - - public void delete() { - try { - this.deleteIntent.send(); - } catch (PendingIntent.CanceledException e) { - throw new RuntimeException(e); - } - } - - @Override - public String toString() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - return "Notification{" + - "packageName='" + mPackageName + "', " + - "title='" + getTitle() + ", " + - "text='" + getText() + "'" + - "} "; - } - return super.toString(); - } - - public static void clone(android.app.Notification from, android.app.Notification to) { - to.when = from.when; - to.icon = from.icon; - to.iconLevel = from.iconLevel; - to.number = from.number; - to.contentIntent = from.contentIntent; - to.deleteIntent = from.deleteIntent; - to.fullScreenIntent = from.fullScreenIntent; - to.tickerText = from.tickerText; - to.tickerView = from.tickerView; - to.contentView = from.contentView; - to.bigContentView = from.bigContentView; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - to.headsUpContentView = from.headsUpContentView; - to.audioAttributes = from.audioAttributes; - to.color = from.color; - to.visibility = from.visibility; - to.category = from.category; - to.publicVersion = from.publicVersion; - } - to.largeIcon = from.largeIcon; - to.sound = from.sound; - to.audioStreamType = from.audioStreamType; - to.vibrate = from.vibrate; - to.ledARGB = from.ledARGB; - to.ledOnMS = from.ledOnMS; - to.ledOffMS = from.ledOffMS; - to.defaults = from.defaults; - to.flags = from.flags; - to.priority = from.priority; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - to.extras = from.extras; - to.actions = from.actions; - } - } - -} diff --git a/automator/src/main/java/com/stardust/notification/Notification.kt b/automator/src/main/java/com/stardust/notification/Notification.kt new file mode 100644 index 00000000..901b9c36 --- /dev/null +++ b/automator/src/main/java/com/stardust/notification/Notification.kt @@ -0,0 +1,96 @@ +package com.stardust.notification + +import android.app.PendingIntent +import android.os.Build +import android.os.Parcel +import android.support.annotation.RequiresApi + +/** + * Created by Stardust on 2017/10/30. + */ + +class Notification private constructor(val packageName: String) : android.app.Notification() { + + val text: String? + @RequiresApi(api = Build.VERSION_CODES.KITKAT) + get() = extras.getString(EXTRA_TEXT) + + val title: String? + @RequiresApi(api = Build.VERSION_CODES.KITKAT) + get() = extras.getString(EXTRA_TITLE) + + fun click() { + try { + this.contentIntent.send() + } catch (e: PendingIntent.CanceledException) { + throw RuntimeException(e) + } + + } + + fun delete() { + try { + this.deleteIntent.send() + } catch (e: PendingIntent.CanceledException) { + throw RuntimeException(e) + } + + } + + override fun toString(): String { + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + "Notification{" + + "packageName='" + packageName + "', " + + "title='" + title + ", " + + "text='" + text + "'" + + "} " + } else super.toString() + } + + companion object { + + fun create(n: android.app.Notification, packageName: String): Notification { + val notification = Notification(packageName) + clone(n, notification) + return notification + } + + @Suppress("DEPRECATION") + fun clone(from: android.app.Notification, to: android.app.Notification) { + to.`when` = from.`when` + to.icon = from.icon + to.iconLevel = from.iconLevel + to.number = from.number + to.contentIntent = from.contentIntent + to.deleteIntent = from.deleteIntent + to.fullScreenIntent = from.fullScreenIntent + to.tickerText = from.tickerText + to.tickerView = from.tickerView + to.contentView = from.contentView + to.bigContentView = from.bigContentView + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + to.headsUpContentView = from.headsUpContentView + to.audioAttributes = from.audioAttributes + to.color = from.color + to.visibility = from.visibility + to.category = from.category + to.publicVersion = from.publicVersion + } + to.largeIcon = from.largeIcon + to.sound = from.sound + to.audioStreamType = from.audioStreamType + to.vibrate = from.vibrate + to.ledARGB = from.ledARGB + to.ledOnMS = from.ledOnMS + to.ledOffMS = from.ledOffMS + to.defaults = from.defaults + to.flags = from.flags + to.priority = from.priority + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + to.extras = from.extras + to.actions = from.actions + } + } + } + +} diff --git a/automator/src/main/java/com/stardust/notification/NotificationListenerService.java b/automator/src/main/java/com/stardust/notification/NotificationListenerService.java deleted file mode 100644 index 242568a4..00000000 --- a/automator/src/main/java/com/stardust/notification/NotificationListenerService.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.stardust.notification; - -import android.app.Notification; -import android.os.Build; -import android.os.Parcel; -import android.service.notification.StatusBarNotification; -import android.support.annotation.RequiresApi; - -import com.stardust.view.accessibility.NotificationListener; - -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; - -/** - * Created by Stardust on 2017/10/30. - */ - -@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2) -public class NotificationListenerService extends android.service.notification.NotificationListenerService { - - private CopyOnWriteArrayList mNotificationListeners = new CopyOnWriteArrayList<>(); - private static NotificationListenerService sInstance; - - @Override - public void onCreate() { - super.onCreate(); - sInstance = this; - } - - public static NotificationListenerService getInstance() { - return sInstance; - } - - @Override - public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) { - onNotificationPosted(sbn); - } - - @Override - public void onNotificationPosted(StatusBarNotification sbn) { - for (NotificationListener listener : mNotificationListeners) { - listener.onNotification(com.stardust.notification.Notification.create( - sbn.getNotification(), sbn.getPackageName())); - } - } - - @Override - public void onNotificationRemoved(StatusBarNotification sbn) { - } - - @Override - public void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap) { - } - - public void addListener(NotificationListener listener) { - mNotificationListeners.add(listener); - } - - public boolean removeListener(NotificationListener listener) { - return mNotificationListeners.remove(listener); - } - - - @Override - public void onDestroy() { - super.onDestroy(); - sInstance = null; - } -} diff --git a/automator/src/main/java/com/stardust/notification/NotificationListenerService.kt b/automator/src/main/java/com/stardust/notification/NotificationListenerService.kt new file mode 100644 index 00000000..f5da80cb --- /dev/null +++ b/automator/src/main/java/com/stardust/notification/NotificationListenerService.kt @@ -0,0 +1,59 @@ +package com.stardust.notification + +import android.app.Notification +import android.os.Build +import android.os.Parcel +import android.service.notification.StatusBarNotification +import android.support.annotation.RequiresApi + +import com.stardust.view.accessibility.NotificationListener +import java.util.concurrent.CopyOnWriteArrayList + +/** + * Created by Stardust on 2017/10/30. + */ + +@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2) +class NotificationListenerService : android.service.notification.NotificationListenerService() { + + private val mNotificationListeners = CopyOnWriteArrayList() + + override fun onCreate() { + super.onCreate() + instance = this + } + + override fun onNotificationPosted(sbn: StatusBarNotification, rankingMap: RankingMap) { + onNotificationPosted(sbn) + } + + override fun onNotificationPosted(sbn: StatusBarNotification) { + for (listener in mNotificationListeners) { + listener.onNotification(com.stardust.notification.Notification.create( + sbn.notification, sbn.packageName)) + } + } + + override fun onNotificationRemoved(sbn: StatusBarNotification) {} + + override fun onNotificationRemoved(sbn: StatusBarNotification, rankingMap: RankingMap) {} + + fun addListener(listener: NotificationListener) { + mNotificationListeners.add(listener) + } + + fun removeListener(listener: NotificationListener): Boolean { + return mNotificationListeners.remove(listener) + } + + + override fun onDestroy() { + super.onDestroy() + instance = null + } + + companion object { + var instance: NotificationListenerService? = null + private set + } +} diff --git a/automator/src/main/java/com/stardust/view/accessibility/AccessibilityDelegate.java b/automator/src/main/java/com/stardust/view/accessibility/AccessibilityDelegate.java deleted file mode 100644 index c99d53cf..00000000 --- a/automator/src/main/java/com/stardust/view/accessibility/AccessibilityDelegate.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.stardust.view.accessibility; - -import android.accessibilityservice.AccessibilityService; -import android.support.annotation.Nullable; -import android.view.accessibility.AccessibilityEvent; -import android.view.accessibility.AccessibilityNodeInfo; - -import java.util.List; -import java.util.Set; - -/** - * Created by Stardust on 2017/2/14. - */ - -public interface AccessibilityDelegate { - - Set ALL_EVENT_TYPES = null; - - boolean onAccessibilityEvent(AccessibilityService service, AccessibilityEvent event); - - /** - * 返回调用onAccessibilityEvent时的EventType的集合。如果需要对所有EventType都有效,返回null。 - * - * @return - */ - @Nullable - Set getEventTypes(); - -} diff --git a/automator/src/main/java/com/stardust/view/accessibility/AccessibilityDelegate.kt b/automator/src/main/java/com/stardust/view/accessibility/AccessibilityDelegate.kt new file mode 100644 index 00000000..7326e77c --- /dev/null +++ b/automator/src/main/java/com/stardust/view/accessibility/AccessibilityDelegate.kt @@ -0,0 +1,27 @@ +package com.stardust.view.accessibility + +import android.accessibilityservice.AccessibilityService +import android.view.accessibility.AccessibilityEvent +import android.view.accessibility.AccessibilityNodeInfo + +/** + * Created by Stardust on 2017/2/14. + */ + +interface AccessibilityDelegate { + + /** + * 返回调用onAccessibilityEvent时的EventType的集合。如果需要对所有EventType都有效,返回null。 + * + * @return + */ + val eventTypes: Set? + + fun onAccessibilityEvent(service: AccessibilityService, event: AccessibilityEvent): Boolean + + companion object { + + val ALL_EVENT_TYPES: Set? = null + } + +} diff --git a/automator/src/main/java/com/stardust/view/accessibility/AccessibilityInfoProvider.java b/automator/src/main/java/com/stardust/view/accessibility/AccessibilityInfoProvider.java deleted file mode 100644 index 4851ee3b..00000000 --- a/automator/src/main/java/com/stardust/view/accessibility/AccessibilityInfoProvider.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.stardust.view.accessibility; - -import android.accessibilityservice.AccessibilityService; -import android.content.ComponentName; -import android.content.Context; -import android.content.pm.ActivityInfo; -import android.content.pm.PackageManager; -import android.view.accessibility.AccessibilityEvent; -import android.view.accessibility.AccessibilityNodeInfo; - -import com.stardust.view.accessibility.AccessibilityDelegate; - -import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; - -/** - * Created by Stardust on 2017/3/9. - */ - -public class AccessibilityInfoProvider implements AccessibilityDelegate { - - - private volatile String mLatestPackage = ""; - private volatile String mLatestActivity = ""; - private PackageManager mPackageManager; - - public AccessibilityInfoProvider(PackageManager packageManager) { - mPackageManager = packageManager; - } - - public String getLatestPackage() { - return mLatestPackage; - } - - public String getLatestActivity() { - return mLatestActivity; - } - - @Override - public boolean onAccessibilityEvent(AccessibilityService service, AccessibilityEvent event) { - if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) { - setLatestComponent(event.getPackageName(), event.getClassName()); - } - return false; - } - - @Override - public Set getEventTypes() { - return ALL_EVENT_TYPES; - } - - private void setLatestComponent(CharSequence latestPackage, CharSequence latestClass) { - if (latestPackage == null || latestClass == null) - return; - String latestPackageStr = latestPackage.toString(); - String latestClassStr = latestClass.toString(); - if (latestClassStr.startsWith("android.view.") || latestClassStr.startsWith("android.widget.")) - return; - try { - ComponentName componentName = new ComponentName(latestPackageStr, latestClassStr); - mLatestActivity = mPackageManager.getActivityInfo(componentName, PackageManager.MATCH_DEFAULT_ONLY).name; - } catch (PackageManager.NameNotFoundException ignored) { - return; - } - mLatestPackage = latestPackage.toString(); - } -} diff --git a/automator/src/main/java/com/stardust/view/accessibility/AccessibilityInfoProvider.kt b/automator/src/main/java/com/stardust/view/accessibility/AccessibilityInfoProvider.kt new file mode 100644 index 00000000..453070fb --- /dev/null +++ b/automator/src/main/java/com/stardust/view/accessibility/AccessibilityInfoProvider.kt @@ -0,0 +1,57 @@ +package com.stardust.view.accessibility + +import android.accessibilityservice.AccessibilityService +import android.content.ComponentName +import android.content.Context +import android.content.pm.ActivityInfo +import android.content.pm.PackageManager +import android.view.accessibility.AccessibilityEvent +import android.view.accessibility.AccessibilityNodeInfo + +import com.stardust.view.accessibility.AccessibilityDelegate + +import java.util.Arrays +import java.util.Collections +import java.util.HashSet + +/** + * Created by Stardust on 2017/3/9. + */ + +class AccessibilityInfoProvider(private val mPackageManager: PackageManager) : AccessibilityDelegate { + + + @Volatile + var latestPackage = "" + private set + @Volatile + var latestActivity = "" + private set + + override val eventTypes: Set? + get() = AccessibilityDelegate.ALL_EVENT_TYPES + + override fun onAccessibilityEvent(service: AccessibilityService, event: AccessibilityEvent): Boolean { + if (event.eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) { + setLatestComponent(event.packageName, event.className) + } + return false + } + + private fun setLatestComponent(latestPackage: CharSequence?, latestClass: CharSequence?) { + if (latestPackage == null || latestClass == null) + return + val latestPackageStr = latestPackage.toString() + val latestClassStr = latestClass.toString() + if (latestClassStr.startsWith("android.view.") || latestClassStr.startsWith("android.widget.")) + return + try { + val componentName = ComponentName(latestPackageStr, latestClassStr) + latestActivity = mPackageManager.getActivityInfo(componentName, PackageManager.MATCH_DEFAULT_ONLY).name + } catch (ignored: PackageManager.NameNotFoundException) { + return + } + + this.latestPackage = latestPackage.toString() + } +} diff --git a/automator/src/main/java/com/stardust/view/accessibility/AccessibilityNodeInfoAllocator.java b/automator/src/main/java/com/stardust/view/accessibility/AccessibilityNodeInfoAllocator.java deleted file mode 100644 index ee4b54d0..00000000 --- a/automator/src/main/java/com/stardust/view/accessibility/AccessibilityNodeInfoAllocator.java +++ /dev/null @@ -1,198 +0,0 @@ -package com.stardust.view.accessibility; - -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat; -import android.util.Log; -import android.view.accessibility.AccessibilityNodeInfo; - -import com.stardust.automator.BuildConfig; - -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * Created by Stardust on 2017/3/22. - */ - -public class AccessibilityNodeInfoAllocator { - - public static final AccessibilityNodeInfoAllocator NONE = new NoOpAllocator(); - - private static final String TAG = "AccessibilityAllocator"; - private static final boolean DEBUG = BuildConfig.DEBUG; - - - private static final AccessibilityNodeInfoAllocator GLOBAL = new AccessibilityNodeInfoAllocator(); - - public static AccessibilityNodeInfoAllocator getGlobal() { - return GLOBAL; - } - - private Map mAccessibilityNodeInfoList = new HashMap<>(); - - public AccessibilityNodeInfo getChild(AccessibilityNodeInfo parent, int i) { - return add(parent.getChild(i)); - } - - public AccessibilityNodeInfoCompat getChild(AccessibilityNodeInfoCompat parent, int i) { - AccessibilityNodeInfoCompat compat = parent.getChild(i); - add((AccessibilityNodeInfo) compat.getInfo()); - return compat; - } - - public AccessibilityNodeInfo getParent(AccessibilityNodeInfo n) { - return add(n.getParent()); - } - - - public AccessibilityNodeInfoCompat getParent(AccessibilityNodeInfoCompat n) { - AccessibilityNodeInfoCompat compat = n.getParent(); - add((AccessibilityNodeInfo) compat.getInfo()); - return compat; - } - - public List findAccessibilityNodeInfosByText(AccessibilityNodeInfo root, String text) { - List list = root.findAccessibilityNodeInfosByText(text); - addAll(list); - return list; - } - - - public List findAccessibilityNodeInfosByText(AccessibilityNodeInfoCompat root, String text) { - List list = root.findAccessibilityNodeInfosByText(text); - addAll(list); - return list; - } - - public List findAccessibilityNodeInfosByViewId(AccessibilityNodeInfo root, String id) { - List list = root.findAccessibilityNodeInfosByViewId(id); - addAll(list); - return list; - } - - - public List findAccessibilityNodeInfosByViewId(AccessibilityNodeInfoCompat root, String id) { - List list = root.findAccessibilityNodeInfosByViewId(id); - addAll(list); - return list; - } - - public void recycle(AccessibilityNodeInfo nodeInfo) { - nodeInfo.recycle(); - mAccessibilityNodeInfoList.remove(nodeInfo); - } - - public void recycle(AccessibilityNodeInfoCompat nodeInfo) { - recycle((AccessibilityNodeInfo) nodeInfo.getInfo()); - } - - public int recycleAll() { - int notRecycledCount = 0; - int size = mAccessibilityNodeInfoList.size(); - for (Map.Entry pair : mAccessibilityNodeInfoList.entrySet()) { - try { - pair.getKey().recycle(); - notRecycledCount++; - if (DEBUG) - Log.w(TAG, pair.getValue()); - } catch (IllegalStateException ignored) { - } - } - Log.v(TAG, "Total: " + size + " Not recycled: " + notRecycledCount); - return notRecycledCount; - } - - public AccessibilityNodeInfo add(@Nullable AccessibilityNodeInfo nodeInfo) { - String stackTrace = DEBUG ? Arrays.toString(Thread.currentThread().getStackTrace()) : null; - if (nodeInfo != null) - mAccessibilityNodeInfoList.put(nodeInfo, stackTrace); - return nodeInfo; - } - - private void addAll(Collection nodeInfos) { - String stackTrace = DEBUG ? Arrays.toString(Thread.currentThread().getStackTrace()) : null; - for (Object nodeInfo : nodeInfos) { - if (nodeInfo instanceof AccessibilityNodeInfo) { - mAccessibilityNodeInfoList.put((AccessibilityNodeInfo) nodeInfo, stackTrace); - } else if (nodeInfo instanceof AccessibilityNodeInfoCompat) { - mAccessibilityNodeInfoList.put((AccessibilityNodeInfo) ((AccessibilityNodeInfoCompat) nodeInfo).getInfo(), stackTrace); - } - } - } - - public static void recycleList(AccessibilityNodeInfo root, List list) { - for (AccessibilityNodeInfo nodeInfo : list) { - if (nodeInfo != root && nodeInfo != null) { - //// FIXME: 2017/5/1 Issue #180 - nodeInfo.recycle(); - } - } - } - - private static class NoOpAllocator extends AccessibilityNodeInfoAllocator { - - @Override - public AccessibilityNodeInfoCompat getParent(AccessibilityNodeInfoCompat n) { - return n.getParent(); - } - - @Override - public AccessibilityNodeInfo getParent(AccessibilityNodeInfo n) { - return n.getParent(); - } - - @Override - public AccessibilityNodeInfoCompat getChild(AccessibilityNodeInfoCompat parent, int i) { - return parent.getChild(i); - } - - @Override - public AccessibilityNodeInfo getChild(AccessibilityNodeInfo parent, int i) { - return parent.getChild(i); - } - - @Override - public List findAccessibilityNodeInfosByViewId(AccessibilityNodeInfoCompat root, String id) { - return root.findAccessibilityNodeInfosByViewId(id); - } - - - @Override - public List findAccessibilityNodeInfosByViewId(AccessibilityNodeInfo root, String id) { - return root.findAccessibilityNodeInfosByViewId(id); - } - - @Override - public List findAccessibilityNodeInfosByText(AccessibilityNodeInfo root, String text) { - return root.findAccessibilityNodeInfosByText(text); - } - - @Override - public List findAccessibilityNodeInfosByText(AccessibilityNodeInfoCompat root, String text) { - return root.findAccessibilityNodeInfosByText(text); - } - - @Override - public void recycle(AccessibilityNodeInfo nodeInfo) { - super.recycle(nodeInfo); - } - - @Override - public void recycle(AccessibilityNodeInfoCompat nodeInfo) { - super.recycle(nodeInfo); - } - - @Override - public int recycleAll() { - return -1; - } - - - } - - -} diff --git a/automator/src/main/java/com/stardust/view/accessibility/AccessibilityNodeInfoAllocator.kt b/automator/src/main/java/com/stardust/view/accessibility/AccessibilityNodeInfoAllocator.kt new file mode 100644 index 00000000..7d057315 --- /dev/null +++ b/automator/src/main/java/com/stardust/view/accessibility/AccessibilityNodeInfoAllocator.kt @@ -0,0 +1,186 @@ +package com.stardust.view.accessibility + +import android.os.Build +import android.support.annotation.RequiresApi +import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat +import android.util.Log +import android.view.accessibility.AccessibilityNodeInfo + +import com.stardust.automator.BuildConfig + +import java.util.Arrays +import java.util.HashMap + +/** + * Created by Stardust on 2017/3/22. + */ + +open class AccessibilityNodeInfoAllocator { + + private val mAccessibilityNodeInfoList = HashMap() + + open fun getChild(parent: AccessibilityNodeInfo, i: Int): AccessibilityNodeInfo? { + return add(parent.getChild(i)) + } + + open fun getChild(parent: AccessibilityNodeInfoCompat, i: Int): AccessibilityNodeInfoCompat { + val compat = parent.getChild(i) + add(compat.info as AccessibilityNodeInfo) + return compat + } + + open fun getParent(n: AccessibilityNodeInfo): AccessibilityNodeInfo? { + return add(n.parent) + } + + + open fun getParent(n: AccessibilityNodeInfoCompat): AccessibilityNodeInfoCompat { + val compat = n.parent + add(compat.info as AccessibilityNodeInfo) + return compat + } + + open fun findAccessibilityNodeInfosByText(root: AccessibilityNodeInfo, text: String): List { + val list = root.findAccessibilityNodeInfosByText(text) + addAll(list) + return list + } + + + open fun findAccessibilityNodeInfosByText(root: AccessibilityNodeInfoCompat, text: String): List { + val list = root.findAccessibilityNodeInfosByText(text) + addAll(list) + return list + } + + @RequiresApi(Build.VERSION_CODES.JELLY_BEAN_MR2) + open fun findAccessibilityNodeInfosByViewId(root: AccessibilityNodeInfo, id: String): List { + val list = root.findAccessibilityNodeInfosByViewId(id) + addAll(list) + return list + } + + + open fun findAccessibilityNodeInfosByViewId(root: AccessibilityNodeInfoCompat, id: String): List { + val list = root.findAccessibilityNodeInfosByViewId(id) + addAll(list) + return list + } + + open fun recycle(nodeInfo: AccessibilityNodeInfo) { + nodeInfo.recycle() + mAccessibilityNodeInfoList.remove(nodeInfo) + } + + open fun recycle(nodeInfo: AccessibilityNodeInfoCompat) { + recycle(nodeInfo.info as AccessibilityNodeInfo) + } + + open fun recycleAll(): Int { + var notRecycledCount = 0 + val size = mAccessibilityNodeInfoList.size + for ((key, value) in mAccessibilityNodeInfoList) { + try { + key.recycle() + notRecycledCount++ + if (DEBUG) + Log.w(TAG, value) + } catch (ignored: IllegalStateException) { + } + + } + Log.v(TAG, "Total: $size Not recycled: $notRecycledCount") + return notRecycledCount + } + + fun add(nodeInfo: AccessibilityNodeInfo?): AccessibilityNodeInfo? { + val stackTrace = if (DEBUG) Arrays.toString(Thread.currentThread().stackTrace) else null + if (nodeInfo != null) + mAccessibilityNodeInfoList[nodeInfo] = stackTrace + return nodeInfo + } + + private fun addAll(nodeInfos: Collection<*>) { + val stackTrace = if (DEBUG) Arrays.toString(Thread.currentThread().stackTrace) else null + for (nodeInfo in nodeInfos) { + if (nodeInfo is AccessibilityNodeInfo) { + mAccessibilityNodeInfoList[nodeInfo] = stackTrace + } else if (nodeInfo is AccessibilityNodeInfoCompat) { + mAccessibilityNodeInfoList[nodeInfo.info as AccessibilityNodeInfo] = stackTrace + } + } + } + + private class NoOpAllocator : AccessibilityNodeInfoAllocator() { + + override fun getParent(n: AccessibilityNodeInfoCompat): AccessibilityNodeInfoCompat { + return n.parent + } + + override fun getParent(n: AccessibilityNodeInfo): AccessibilityNodeInfo? { + return n.parent + } + + override fun getChild(parent: AccessibilityNodeInfoCompat, i: Int): AccessibilityNodeInfoCompat { + return parent.getChild(i) + } + + override fun getChild(parent: AccessibilityNodeInfo, i: Int): AccessibilityNodeInfo? { + return parent.getChild(i) + } + + override fun findAccessibilityNodeInfosByViewId(root: AccessibilityNodeInfoCompat, id: String): List { + return root.findAccessibilityNodeInfosByViewId(id) + } + + + @RequiresApi(Build.VERSION_CODES.JELLY_BEAN_MR2) + override fun findAccessibilityNodeInfosByViewId(root: AccessibilityNodeInfo, id: String): List { + return root.findAccessibilityNodeInfosByViewId(id) + } + + override fun findAccessibilityNodeInfosByText(root: AccessibilityNodeInfo, text: String): List { + return root.findAccessibilityNodeInfosByText(text) + } + + override fun findAccessibilityNodeInfosByText(root: AccessibilityNodeInfoCompat, text: String): List { + return root.findAccessibilityNodeInfosByText(text) + } + + override fun recycle(nodeInfo: AccessibilityNodeInfo) { + super.recycle(nodeInfo) + } + + override fun recycle(nodeInfo: AccessibilityNodeInfoCompat) { + super.recycle(nodeInfo) + } + + override fun recycleAll(): Int { + return -1 + } + + + } + + companion object { + + val NONE: AccessibilityNodeInfoAllocator = NoOpAllocator() + + private val TAG = "AccessibilityAllocator" + private val DEBUG = BuildConfig.DEBUG + + + val global = AccessibilityNodeInfoAllocator() + + fun recycleList(root: AccessibilityNodeInfo, list: List) { + for (nodeInfo in list) { + if (nodeInfo !== root && nodeInfo != null) { + //// FIXME: 2017/5/1 Issue #180 + nodeInfo.recycle() + } + } + } + } + + +} diff --git a/automator/src/main/java/com/stardust/view/accessibility/AccessibilityNodeInfoHelper.java b/automator/src/main/java/com/stardust/view/accessibility/AccessibilityNodeInfoHelper.java deleted file mode 100644 index e84d2e71..00000000 --- a/automator/src/main/java/com/stardust/view/accessibility/AccessibilityNodeInfoHelper.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.stardust.view.accessibility; - -import android.graphics.Rect; -import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat; -import android.view.accessibility.AccessibilityNodeInfo; - -import com.stardust.automator.UiObject; - -/** - * Created by Stardust on 2017/3/6. - */ - -public class AccessibilityNodeInfoHelper { - - /** - * Returns the node's bounds clipped to the size of the display - * - * @param node - * @param width pixel width of the display - * @param height pixel height of the display - * @return null if node is null, else a Rect containing visible bounds - */ - public static Rect getVisibleBoundsInScreen(AccessibilityNodeInfo node, int width, int height) { - if (node == null) { - return null; - } - // targeted node's bounds - Rect nodeRect = new Rect(); - node.getBoundsInScreen(nodeRect); - - Rect displayRect = new Rect(); - displayRect.top = 0; - displayRect.left = 0; - displayRect.right = width; - displayRect.bottom = height; - boolean intersect = nodeRect.intersect(displayRect); - return nodeRect; - } - - public static Rect getBoundsInParent(AccessibilityNodeInfo nodeInfo) { - Rect rect = new Rect(); - nodeInfo.getBoundsInParent(rect); - return rect; - } - - public static Rect getBoundsInScreen(AccessibilityNodeInfo nodeInfo) { - Rect rect = new Rect(); - nodeInfo.getBoundsInScreen(rect); - return rect; - } - - public static Rect getBoundsInScreen(AccessibilityNodeInfoCompat nodeInfo) { - Rect rect = new Rect(); - nodeInfo.getBoundsInScreen(rect); - return rect; - } - - public static Rect getBoundsInParent(AccessibilityNodeInfoCompat nodeInfo) { - Rect rect = new Rect(); - nodeInfo.getBoundsInParent(rect); - return rect; - } -} diff --git a/automator/src/main/java/com/stardust/view/accessibility/AccessibilityNodeInfoHelper.kt b/automator/src/main/java/com/stardust/view/accessibility/AccessibilityNodeInfoHelper.kt new file mode 100644 index 00000000..01efdb71 --- /dev/null +++ b/automator/src/main/java/com/stardust/view/accessibility/AccessibilityNodeInfoHelper.kt @@ -0,0 +1,63 @@ +package com.stardust.view.accessibility + +import android.graphics.Rect +import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat +import android.view.accessibility.AccessibilityNodeInfo + +import com.stardust.automator.UiObject + +/** + * Created by Stardust on 2017/3/6. + */ + +object AccessibilityNodeInfoHelper { + + /** + * Returns the node's bounds clipped to the size of the display + * + * @param node + * @param width pixel width of the display + * @param height pixel height of the display + * @return null if node is null, else a Rect containing visible bounds + */ + fun getVisibleBoundsInScreen(node: AccessibilityNodeInfo?, width: Int, height: Int): Rect? { + if (node == null) { + return null + } + // targeted node's bounds + val nodeRect = Rect() + node.getBoundsInScreen(nodeRect) + + val displayRect = Rect() + displayRect.top = 0 + displayRect.left = 0 + displayRect.right = width + displayRect.bottom = height + val intersect = nodeRect.intersect(displayRect) + return nodeRect + } + + fun getBoundsInParent(nodeInfo: AccessibilityNodeInfo): Rect { + val rect = Rect() + nodeInfo.getBoundsInParent(rect) + return rect + } + + fun getBoundsInScreen(nodeInfo: AccessibilityNodeInfo): Rect { + val rect = Rect() + nodeInfo.getBoundsInScreen(rect) + return rect + } + + fun getBoundsInScreen(nodeInfo: AccessibilityNodeInfoCompat): Rect { + val rect = Rect() + nodeInfo.getBoundsInScreen(rect) + return rect + } + + fun getBoundsInParent(nodeInfo: AccessibilityNodeInfoCompat): Rect { + val rect = Rect() + nodeInfo.getBoundsInParent(rect) + return rect + } +} diff --git a/automator/src/main/java/com/stardust/view/accessibility/AccessibilityNotificationObserver.java b/automator/src/main/java/com/stardust/view/accessibility/AccessibilityNotificationObserver.java deleted file mode 100644 index e17478a7..00000000 --- a/automator/src/main/java/com/stardust/view/accessibility/AccessibilityNotificationObserver.java +++ /dev/null @@ -1,146 +0,0 @@ -package com.stardust.view.accessibility; - -import android.accessibilityservice.*; -import android.content.Context; -import android.support.annotation.Nullable; -import android.util.Log; -import android.view.accessibility.AccessibilityEvent; - -import com.stardust.notification.Notification; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Set; -import java.util.concurrent.CopyOnWriteArrayList; - -/** - * Created by Stardust on 2017/11/3. - */ - -public class AccessibilityNotificationObserver implements NotificationListener, AccessibilityDelegate { - - public class Toast { - public final List texts; - public final String packageName; - - public Toast(String packageName, List texts) { - this.texts = new ArrayList<>(texts.size()); - for (CharSequence t : texts) { - if (t != null) { - this.texts.add(t.toString()); - } - } - this.packageName = packageName; - } - - public String getText() { - if (texts.isEmpty()) { - return null; - } - CharSequence text = texts.get(0); - if (text == null) { - return null; - } - return text.toString(); - } - - public List getTexts() { - return texts; - } - - public String getPackageName() { - return packageName; - } - - @Override - public String toString() { - return "Toast{" + - "texts=" + texts + - ", packageName='" + packageName + '\'' + - '}'; - } - } - - public interface ToastListener { - void onToast(Toast toast); - } - - private static final Set EVENT_TYPES = Collections.singleton(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED); - - private static final String TAG = "NotificationObserver"; - private static final String[] EMPTY = new String[0]; - - private Context mContext; - private CopyOnWriteArrayList mNotificationListeners = new CopyOnWriteArrayList<>(); - private CopyOnWriteArrayList mToastListeners = new CopyOnWriteArrayList<>(); - - public AccessibilityNotificationObserver(Context context) { - mContext = context; - } - - - public void addNotificationListener(NotificationListener listener) { - mNotificationListeners.add(listener); - } - - public boolean removeNotificationListener(NotificationListener listener) { - return mNotificationListeners.remove(listener); - } - - - public void addToastListener(ToastListener listener) { - mToastListeners.add(listener); - } - - public boolean removeToastListener(ToastListener listener) { - return mToastListeners.remove(listener); - } - - @Override - public boolean onAccessibilityEvent(android.accessibilityservice.AccessibilityService service, AccessibilityEvent event) { - if (event.getParcelableData() instanceof Notification) { - android.app.Notification notification = (android.app.Notification) event.getParcelableData(); - Log.d(TAG, "onNotification: " + notification + "; " + event); - onNotification(Notification.create(notification, event.getPackageName().toString())); - } else { - List list = event.getText(); - Log.d(TAG, "onNotification: " + list + "; " + event); - if (event.getPackageName().equals(mContext.getPackageName())) { - return false; - } - if (list != null) { - onToast(event, new Toast(event.getPackageName().toString(), list)); - } - } - - return false; - } - - private void onToast(AccessibilityEvent event, Toast toast) { - for (ToastListener listener : mToastListeners) { - try { - listener.onToast(toast); - } catch (Exception e) { - Log.e(TAG, "Error onNotification: " + toast + " Listener: " + listener, e); - } - } - } - - @Nullable - @Override - public Set getEventTypes() { - return EVENT_TYPES; - } - - @Override - public void onNotification(Notification notification) { - for (NotificationListener listener : mNotificationListeners) { - try { - listener.onNotification(notification); - } catch (Exception e) { - Log.e(TAG, "Error onNotification: " + notification + " Listener: " + listener, e); - } - } - } -} diff --git a/automator/src/main/java/com/stardust/view/accessibility/AccessibilityNotificationObserver.kt b/automator/src/main/java/com/stardust/view/accessibility/AccessibilityNotificationObserver.kt new file mode 100644 index 00000000..820cdf52 --- /dev/null +++ b/automator/src/main/java/com/stardust/view/accessibility/AccessibilityNotificationObserver.kt @@ -0,0 +1,120 @@ +package com.stardust.view.accessibility + +import android.accessibilityservice.* +import android.content.Context +import android.util.Log +import android.view.accessibility.AccessibilityEvent + +import com.stardust.notification.Notification + +import java.util.ArrayList +import java.util.Collections +import java.util.concurrent.CopyOnWriteArrayList + +/** + * Created by Stardust on 2017/11/3. + */ + +class AccessibilityNotificationObserver(private val mContext: Context) : NotificationListener, AccessibilityDelegate { + private val mNotificationListeners = CopyOnWriteArrayList() + private val mToastListeners = CopyOnWriteArrayList() + + override val eventTypes: Set? + get() = EVENT_TYPES + + inner class Toast(val packageName: String, texts: List) { + val texts: MutableList + + val text: String? + get() { + return if (texts.isEmpty()) { + null + } else texts[0] + } + + init { + this.texts = ArrayList(texts.size) + for (t in texts) { + this.texts.add(t.toString()) + } + } + + override fun toString(): String { + return "Toast{" + + "texts=" + texts + + ", packageName='" + packageName + '\''.toString() + + '}'.toString() + } + } + + interface ToastListener { + fun onToast(toast: Toast) + } + + + fun addNotificationListener(listener: NotificationListener) { + mNotificationListeners.add(listener) + } + + fun removeNotificationListener(listener: NotificationListener): Boolean { + return mNotificationListeners.remove(listener) + } + + + fun addToastListener(listener: ToastListener) { + mToastListeners.add(listener) + } + + fun removeToastListener(listener: ToastListener): Boolean { + return mToastListeners.remove(listener) + } + + override fun onAccessibilityEvent(service: android.accessibilityservice.AccessibilityService, event: AccessibilityEvent): Boolean { + if (event.parcelableData is Notification) { + val notification = event.parcelableData as android.app.Notification + Log.d(TAG, "onNotification: $notification; $event") + onNotification(Notification.create(notification, event.packageName.toString())) + } else { + val list = event.text + Log.d(TAG, "onNotification: $list; $event") + if (event.packageName == mContext.packageName) { + return false + } + if (list != null) { + onToast(event, Toast(event.packageName.toString(), list)) + } + } + + return false + } + + private fun onToast(event: AccessibilityEvent, toast: Toast) { + for (listener in mToastListeners) { + try { + listener.onToast(toast) + } catch (e: Exception) { + Log.e(TAG, "Error onNotification: $toast Listener: $listener", e) + } + + } + } + + override fun onNotification(notification: Notification) { + for (listener in mNotificationListeners) { + try { + listener.onNotification(notification) + } catch (e: Exception) { + Log.e(TAG, "Error onNotification: $notification Listener: $listener", e) + } + + } + } + + companion object { + + private val EVENT_TYPES = setOf(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED) + + private val TAG = "NotificationObserver" + private val EMPTY = arrayOfNulls(0) + } +} diff --git a/automator/src/main/java/com/stardust/view/accessibility/AccessibilityService.java b/automator/src/main/java/com/stardust/view/accessibility/AccessibilityService.java deleted file mode 100644 index 5a993948..00000000 --- a/automator/src/main/java/com/stardust/view/accessibility/AccessibilityService.java +++ /dev/null @@ -1,175 +0,0 @@ -package com.stardust.view.accessibility; - -import android.os.Build; -import android.support.annotation.Nullable; -import android.util.Log; -import android.view.KeyEvent; -import android.view.accessibility.AccessibilityEvent; -import android.view.accessibility.AccessibilityNodeInfo; - -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.SortedMap; -import java.util.TreeMap; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.locks.Condition; -import java.util.concurrent.locks.ReentrantLock; - -/** - * Created by Stardust on 2017/5/2. - */ - -public class AccessibilityService extends android.accessibilityservice.AccessibilityService { - - private static final String TAG = "AccessibilityService"; - - private static final SortedMap mDelegates = new TreeMap<>(); - private static final ReentrantLock LOCK = new ReentrantLock(); - private static final Condition ENABLED = LOCK.newCondition(); - private static AccessibilityService instance; - private static final OnKeyListener.Observer stickOnKeyObserver = new OnKeyListener.Observer(); - private static boolean containsAllEventTypes = false; - private static final Set eventTypes = new HashSet<>(); - private OnKeyListener.Observer mOnKeyObserver = new OnKeyListener.Observer(); - private KeyInterceptor.Observer mKeyInterrupterObserver = new KeyInterceptor.Observer(); - private ExecutorService mKeyEventExecutor; - private AccessibilityNodeInfo mFastRootInActiveWindow; - - public static void addDelegate(int uniquePriority, AccessibilityDelegate delegate) { - mDelegates.put(uniquePriority, delegate); - Set set = delegate.getEventTypes(); - if (set == null) - containsAllEventTypes = true; - else - eventTypes.addAll(set); - } - - public static AccessibilityService getInstance() { - return instance; - } - - @Override - public void onAccessibilityEvent(final AccessibilityEvent event) { - instance = this; - //Log.v(TAG, "onAccessibilityEvent: " + event); - if (!containsAllEventTypes && !eventTypes.contains(event.getEventType())) - return; - int type = event.getEventType(); - if (type == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED || - type == AccessibilityEvent.TYPE_VIEW_FOCUSED) { - AccessibilityNodeInfo root = getRootInActiveWindow(); - if (root != null) { - mFastRootInActiveWindow = root; - } - } - - for (Map.Entry entry : mDelegates.entrySet()) { - AccessibilityDelegate delegate = entry.getValue(); - Set types = delegate.getEventTypes(); - if (types != null && !delegate.getEventTypes().contains(event.getEventType())) - continue; - //long start = System.currentTimeMillis(); - if (delegate.onAccessibilityEvent(AccessibilityService.this, event)) - break; - //Log.v(TAG, "millis: " + (System.currentTimeMillis() - start) + " delegate: " + entry.getValue().getClass().getName()); - } - } - - - @Override - public void onInterrupt() { - - } - - @Override - protected boolean onKeyEvent(final KeyEvent event) { - if (mKeyEventExecutor == null) { - mKeyEventExecutor = Executors.newSingleThreadExecutor(); - } - mKeyEventExecutor.execute(() -> { - stickOnKeyObserver.onKeyEvent(event.getKeyCode(), event); - mOnKeyObserver.onKeyEvent(event.getKeyCode(), event); - }); - return mKeyInterrupterObserver.onInterceptKeyEvent(event); - } - - public KeyInterceptor.Observer getKeyInterrupterObserver() { - return mKeyInterrupterObserver; - } - - public OnKeyListener.Observer getOnKeyObserver() { - return mOnKeyObserver; - } - - @Override - public AccessibilityNodeInfo getRootInActiveWindow() { - try { - return super.getRootInActiveWindow(); - } catch (Exception e) { - return null; - } - } - - @Override - public void onDestroy() { - instance = null; - if (mKeyEventExecutor != null) - mKeyEventExecutor.shutdownNow(); - super.onDestroy(); - } - - - @Override - protected void onServiceConnected() { - Log.v(TAG, "onServiceConnected: " + getServiceInfo().toString()); - instance = this; - super.onServiceConnected(); - LOCK.lock(); - ENABLED.signalAll(); - LOCK.unlock(); - // FIXME: 2017/2/12 有时在无障碍中开启服务后这里不会调用服务也不会运行,安卓的BUG??? - } - - - @Nullable - public AccessibilityNodeInfo fastRootInActiveWindow() { - return mFastRootInActiveWindow; - } - - public static boolean disable() { - if (instance != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - instance.disableSelf(); - return true; - } - return false; - } - - public static boolean waitForEnabled(long timeOut) { - if (instance != null) - return true; - LOCK.lock(); - try { - if (instance != null) - return true; - if (timeOut == -1) { - ENABLED.await(); - return true; - } - return ENABLED.await(timeOut, TimeUnit.MILLISECONDS); - } catch (InterruptedException e) { - e.printStackTrace(); - return false; - } finally { - LOCK.unlock(); - } - } - - public static OnKeyListener.Observer getStickOnKeyObserver() { - return stickOnKeyObserver; - } - - -} diff --git a/automator/src/main/java/com/stardust/view/accessibility/AccessibilityService.kt b/automator/src/main/java/com/stardust/view/accessibility/AccessibilityService.kt new file mode 100644 index 00000000..ddb1eaae --- /dev/null +++ b/automator/src/main/java/com/stardust/view/accessibility/AccessibilityService.kt @@ -0,0 +1,152 @@ +package com.stardust.view.accessibility + +import android.os.Build +import android.util.Log +import android.view.KeyEvent +import android.view.accessibility.AccessibilityEvent +import android.view.accessibility.AccessibilityNodeInfo + +import java.util.HashSet +import java.util.SortedMap +import java.util.TreeMap +import java.util.concurrent.ExecutorService +import java.util.concurrent.Executors +import java.util.concurrent.TimeUnit +import java.util.concurrent.locks.Condition +import java.util.concurrent.locks.ReentrantLock + +/** + * Created by Stardust on 2017/5/2. + */ + +open class AccessibilityService : android.accessibilityservice.AccessibilityService() { + val onKeyObserver = OnKeyListener.Observer() + val keyInterrupterObserver = KeyInterceptor.Observer() + private var mKeyEventExecutor: ExecutorService? = null + private var mFastRootInActiveWindow: AccessibilityNodeInfo? = null + + override fun onAccessibilityEvent(event: AccessibilityEvent) { + instance = this + //Log.v(TAG, "onAccessibilityEvent: " + event); + if (!containsAllEventTypes && !eventTypes.contains(event.eventType)) + return + val type = event.eventType + if (type == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED || type == AccessibilityEvent.TYPE_VIEW_FOCUSED) { + val root = rootInActiveWindow + if (root != null) { + mFastRootInActiveWindow = root + } + } + + for ((_, delegate) in mDelegates) { + val types = delegate.eventTypes + if (types != null && !delegate.eventTypes!!.contains(event.eventType)) + continue + //long start = System.currentTimeMillis(); + if (delegate.onAccessibilityEvent(this@AccessibilityService, event)) + break + //Log.v(TAG, "millis: " + (System.currentTimeMillis() - start) + " delegate: " + entry.getValue().getClass().getName()); + } + } + + + override fun onInterrupt() { + + } + + override fun onKeyEvent(event: KeyEvent): Boolean { + if (mKeyEventExecutor == null) { + mKeyEventExecutor = Executors.newSingleThreadExecutor() + } + mKeyEventExecutor!!.execute { + stickOnKeyObserver.onKeyEvent(event.keyCode, event) + onKeyObserver.onKeyEvent(event.keyCode, event) + } + return keyInterrupterObserver.onInterceptKeyEvent(event) + } + + override fun getRootInActiveWindow(): AccessibilityNodeInfo? { + try { + return super.getRootInActiveWindow() + } catch (e: Exception) { + return null + } + + } + + override fun onDestroy() { + instance = null + if (mKeyEventExecutor != null) + mKeyEventExecutor!!.shutdownNow() + super.onDestroy() + } + + + override fun onServiceConnected() { + Log.v(TAG, "onServiceConnected: " + serviceInfo.toString()) + instance = this + super.onServiceConnected() + LOCK.lock() + ENABLED.signalAll() + LOCK.unlock() + // FIXME: 2017/2/12 有时在无障碍中开启服务后这里不会调用服务也不会运行,安卓的BUG??? + } + + + fun fastRootInActiveWindow(): AccessibilityNodeInfo? { + return mFastRootInActiveWindow + } + + companion object { + + private val TAG = "AccessibilityService" + + private val mDelegates = TreeMap() + private val LOCK = ReentrantLock() + private val ENABLED = LOCK.newCondition() + var instance: AccessibilityService? = null + private set + val stickOnKeyObserver = OnKeyListener.Observer() + private var containsAllEventTypes = false + private val eventTypes = HashSet() + + fun addDelegate(uniquePriority: Int, delegate: AccessibilityDelegate) { + mDelegates[uniquePriority] = delegate + val set = delegate.eventTypes + if (set == null) + containsAllEventTypes = true + else + eventTypes.addAll(set) + } + + fun disable(): Boolean { + if (instance != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + instance!!.disableSelf() + return true + } + return false + } + + fun waitForEnabled(timeOut: Long): Boolean { + if (instance != null) + return true + LOCK.lock() + try { + if (instance != null) + return true + if (timeOut == -1L) { + ENABLED.await() + return true + } + return ENABLED.await(timeOut, TimeUnit.MILLISECONDS) + } catch (e: InterruptedException) { + e.printStackTrace() + return false + } finally { + LOCK.unlock() + } + } + } + + +} diff --git a/automator/src/main/java/com/stardust/view/accessibility/AccessibilityServiceUtils.java b/automator/src/main/java/com/stardust/view/accessibility/AccessibilityServiceUtils.java deleted file mode 100644 index 35355bb0..00000000 --- a/automator/src/main/java/com/stardust/view/accessibility/AccessibilityServiceUtils.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.stardust.view.accessibility; - -import android.accessibilityservice.AccessibilityService; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.provider.Settings; -import android.text.TextUtils; - -import java.util.Locale; - - -/** - * Created by Stardust on 2017/1/26. - */ - -public class AccessibilityServiceUtils { - - public static void goToAccessibilitySetting(Context context) { - context.startActivity(new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); - } - - public static boolean isAccessibilityServiceEnabled(Context context, Class accessibilityService) { - ComponentName expectedComponentName = new ComponentName(context, accessibilityService); - - String enabledServicesSetting = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES); - if (enabledServicesSetting == null) - return false; - - TextUtils.SimpleStringSplitter colonSplitter = new TextUtils.SimpleStringSplitter(':'); - colonSplitter.setString(enabledServicesSetting); - - while (colonSplitter.hasNext()) { - String componentNameString = colonSplitter.next(); - ComponentName enabledService = ComponentName.unflattenFromString(componentNameString); - - if (enabledService != null && enabledService.equals(expectedComponentName)) - return true; - } - - return false; - } - - -} diff --git a/automator/src/main/java/com/stardust/view/accessibility/AccessibilityServiceUtils.kt b/automator/src/main/java/com/stardust/view/accessibility/AccessibilityServiceUtils.kt new file mode 100644 index 00000000..aa3685b6 --- /dev/null +++ b/automator/src/main/java/com/stardust/view/accessibility/AccessibilityServiceUtils.kt @@ -0,0 +1,44 @@ +package com.stardust.view.accessibility + +import android.accessibilityservice.AccessibilityService +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.provider.Settings +import android.text.TextUtils + +import java.util.Locale + + +/** + * Created by Stardust on 2017/1/26. + */ + +object AccessibilityServiceUtils { + + fun goToAccessibilitySetting(context: Context) { + context.startActivity(Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)) + } + + fun isAccessibilityServiceEnabled(context: Context, accessibilityService: Class): Boolean { + val expectedComponentName = ComponentName(context, accessibilityService) + + val enabledServicesSetting = Settings.Secure.getString(context.contentResolver, Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES) + ?: return false + + val colonSplitter = TextUtils.SimpleStringSplitter(':') + colonSplitter.setString(enabledServicesSetting) + + while (colonSplitter.hasNext()) { + val componentNameString = colonSplitter.next() + val enabledService = ComponentName.unflattenFromString(componentNameString) + + if (enabledService != null && enabledService == expectedComponentName) + return true + } + + return false + } + + +} diff --git a/automator/src/main/java/com/stardust/view/accessibility/KeyInterceptor.java b/automator/src/main/java/com/stardust/view/accessibility/KeyInterceptor.java deleted file mode 100644 index 4bee0852..00000000 --- a/automator/src/main/java/com/stardust/view/accessibility/KeyInterceptor.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.stardust.view.accessibility; - -import android.view.KeyEvent; - -import java.util.concurrent.CopyOnWriteArrayList; - -/** - * Created by Stardust on 2018/2/27. - */ - -public interface KeyInterceptor { - - boolean onInterceptKeyEvent(KeyEvent event); - - class Observer implements KeyInterceptor { - private CopyOnWriteArrayList mKeyInterceptors = new CopyOnWriteArrayList<>(); - - public void addKeyInterrupter(KeyInterceptor interrupter){ - mKeyInterceptors.add(interrupter); - } - - public boolean removeKeyInterrupter(KeyInterceptor interrupter){ - return mKeyInterceptors.remove(interrupter); - } - - - @Override - public boolean onInterceptKeyEvent(KeyEvent event) { - for(KeyInterceptor interrupter : mKeyInterceptors){ - try { - if(interrupter.onInterceptKeyEvent(event)){ - return true; - } - }catch (Exception e){ - e.printStackTrace(); - } - } - return false; - } - } -} diff --git a/automator/src/main/java/com/stardust/view/accessibility/KeyInterceptor.kt b/automator/src/main/java/com/stardust/view/accessibility/KeyInterceptor.kt new file mode 100644 index 00000000..235d370c --- /dev/null +++ b/automator/src/main/java/com/stardust/view/accessibility/KeyInterceptor.kt @@ -0,0 +1,41 @@ +package com.stardust.view.accessibility + +import android.view.KeyEvent + +import java.util.concurrent.CopyOnWriteArrayList + +/** + * Created by Stardust on 2018/2/27. + */ + +interface KeyInterceptor { + + fun onInterceptKeyEvent(event: KeyEvent): Boolean + + class Observer : KeyInterceptor { + private val mKeyInterceptors = CopyOnWriteArrayList() + + fun addKeyInterrupter(interrupter: KeyInterceptor) { + mKeyInterceptors.add(interrupter) + } + + fun removeKeyInterrupter(interrupter: KeyInterceptor): Boolean { + return mKeyInterceptors.remove(interrupter) + } + + + override fun onInterceptKeyEvent(event: KeyEvent): Boolean { + for (interrupter in mKeyInterceptors) { + try { + if (interrupter.onInterceptKeyEvent(event)) { + return true + } + } catch (e: Exception) { + e.printStackTrace() + } + + } + return false + } + } +} diff --git a/automator/src/main/java/com/stardust/view/accessibility/LayoutInspectService.java b/automator/src/main/java/com/stardust/view/accessibility/LayoutInspectService.java deleted file mode 100644 index 9d72b7e5..00000000 --- a/automator/src/main/java/com/stardust/view/accessibility/LayoutInspectService.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.stardust.view.accessibility; - -import android.accessibilityservice.AccessibilityServiceInfo; -import android.view.accessibility.AccessibilityNodeInfo; - -/** - * Created by Stardust on 2017/7/13. - */ - -public class LayoutInspectService extends AccessibilityService { - - private static LayoutInspectService instance; - - public static LayoutInspectService getInstance() { - return instance; - } - - - @Override - protected void onServiceConnected() { - AccessibilityServiceInfo info = getServiceInfo(); - info.flags |= AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS; - setServiceInfo(info); - super.onServiceConnected(); - } -} - diff --git a/automator/src/main/java/com/stardust/view/accessibility/LayoutInspectService.kt b/automator/src/main/java/com/stardust/view/accessibility/LayoutInspectService.kt new file mode 100644 index 00000000..c44358f6 --- /dev/null +++ b/automator/src/main/java/com/stardust/view/accessibility/LayoutInspectService.kt @@ -0,0 +1,25 @@ +package com.stardust.view.accessibility + +import android.accessibilityservice.AccessibilityServiceInfo +import android.view.accessibility.AccessibilityNodeInfo + +/** + * Created by Stardust on 2017/7/13. + */ + +class LayoutInspectService : AccessibilityService() { + + + override fun onServiceConnected() { + val info = serviceInfo + info.flags = info.flags or AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS + serviceInfo = info + super.onServiceConnected() + } + + companion object { + + val instance: LayoutInspectService? = null + } +} + diff --git a/automator/src/main/java/com/stardust/view/accessibility/LayoutInspector.java b/automator/src/main/java/com/stardust/view/accessibility/LayoutInspector.java deleted file mode 100644 index d3ef99d8..00000000 --- a/automator/src/main/java/com/stardust/view/accessibility/LayoutInspector.java +++ /dev/null @@ -1,96 +0,0 @@ -package com.stardust.view.accessibility; - -import android.content.Context; -import android.os.Build; -import android.support.annotation.RequiresApi; -import android.util.Log; -import android.view.accessibility.AccessibilityNodeInfo; - -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.Executor; -import java.util.concurrent.Executors; - -/** - * Created by Stardust on 2017/3/10. - */ - -public class LayoutInspector { - - public interface CaptureAvailableListener { - void onCaptureAvailable(NodeInfo capture); - } - - private static final String LOG_TAG = LayoutInspector.class.getSimpleName(); - private volatile NodeInfo mCapture; - private volatile boolean mDumping = false; - private Executor mExecutor = Executors.newSingleThreadExecutor(); - private CopyOnWriteArrayList mCaptureAvailableListeners = new CopyOnWriteArrayList<>(); - private final Context mContext; - - public LayoutInspector(Context context) { - mContext = context; - } - - public boolean captureCurrentWindow() { - AccessibilityService service = AccessibilityService.getInstance(); - if (service == null) { - Log.d(LOG_TAG, "captureCurrentWindow: service = null"); - mCapture = null; - return false; - } - final AccessibilityNodeInfo root = getRootInActiveWindow(service); - if (root == null) { - Log.d(LOG_TAG, "captureCurrentWindow: root = null"); - mCapture = null; - return false; - } - mExecutor.execute(() -> { - mDumping = true; - mCapture = NodeInfo.capture(mContext, root); - mDumping = false; - for (CaptureAvailableListener l : mCaptureAvailableListeners) { - l.onCaptureAvailable(mCapture); - } - }); - return true; - } - - public void addCaptureAvailableListener(CaptureAvailableListener l){ - mCaptureAvailableListeners.add(l); - } - - public boolean removeCaptureAvailableListener(CaptureAvailableListener l){ - return mCaptureAvailableListeners.remove(l); - } - - private AccessibilityNodeInfo getRootInActiveWindow(AccessibilityService service) { - AccessibilityNodeInfo root = service.getRootInActiveWindow(); - if (root == null) - return service.fastRootInActiveWindow(); - return root; - - } - - @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2) - private void refreshChildList(AccessibilityNodeInfo root) { - if (root == null) - return; - root.refresh(); - int childCount = root.getChildCount(); - for (int i = 0; i < childCount; i++) { - refreshChildList(root.getChild(i)); - } - } - - public boolean isDumping() { - return mDumping; - } - - public void clearCapture() { - mCapture = null; - } - - public NodeInfo getCapture() { - return mCapture; - } -} diff --git a/automator/src/main/java/com/stardust/view/accessibility/LayoutInspector.kt b/automator/src/main/java/com/stardust/view/accessibility/LayoutInspector.kt new file mode 100644 index 00000000..81b502a2 --- /dev/null +++ b/automator/src/main/java/com/stardust/view/accessibility/LayoutInspector.kt @@ -0,0 +1,87 @@ +package com.stardust.view.accessibility + +import android.content.Context +import android.os.Build +import android.support.annotation.RequiresApi +import android.util.Log +import android.view.accessibility.AccessibilityNodeInfo + +import java.util.concurrent.CopyOnWriteArrayList +import java.util.concurrent.Executor +import java.util.concurrent.Executors + +/** + * Created by Stardust on 2017/3/10. + */ + +class LayoutInspector(private val mContext: Context) { + @Volatile + var capture: NodeInfo? = null + private set + @Volatile + var isDumping = false + private set + private val mExecutor = Executors.newSingleThreadExecutor() + private val mCaptureAvailableListeners = CopyOnWriteArrayList() + + interface CaptureAvailableListener { + fun onCaptureAvailable(capture: NodeInfo?) + } + + fun captureCurrentWindow(): Boolean { + val service = AccessibilityService.instance + if (service == null) { + Log.d(LOG_TAG, "captureCurrentWindow: service = null") + capture = null + return false + } + val root = getRootInActiveWindow(service) + if (root == null) { + Log.d(LOG_TAG, "captureCurrentWindow: root = null") + capture = null + return false + } + mExecutor.execute { + isDumping = true + capture = NodeInfo.capture(mContext, root) + isDumping = false + for (l in mCaptureAvailableListeners) { + l.onCaptureAvailable(capture) + } + } + return true + } + + fun addCaptureAvailableListener(l: CaptureAvailableListener) { + mCaptureAvailableListeners.add(l) + } + + fun removeCaptureAvailableListener(l: CaptureAvailableListener): Boolean { + return mCaptureAvailableListeners.remove(l) + } + + private fun getRootInActiveWindow(service: AccessibilityService): AccessibilityNodeInfo? { + return service.rootInActiveWindow ?: return service.fastRootInActiveWindow() + + } + + @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2) + private fun refreshChildList(root: AccessibilityNodeInfo?) { + if (root == null) + return + root.refresh() + val childCount = root.childCount + for (i in 0 until childCount) { + refreshChildList(root.getChild(i)) + } + } + + fun clearCapture() { + capture = null + } + + companion object { + + private val LOG_TAG = LayoutInspector::class.java!!.getSimpleName() + } +} diff --git a/automator/src/main/java/com/stardust/view/accessibility/NodeInfo.java b/automator/src/main/java/com/stardust/view/accessibility/NodeInfo.java deleted file mode 100644 index 80b40c8c..00000000 --- a/automator/src/main/java/com/stardust/view/accessibility/NodeInfo.java +++ /dev/null @@ -1,199 +0,0 @@ -package com.stardust.view.accessibility; - -import android.content.Context; -import android.content.pm.PackageManager; -import android.content.res.Resources; -import android.graphics.Rect; -import android.support.annotation.Keep; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat; -import android.view.accessibility.AccessibilityNodeInfo; - -import com.stardust.automator.UiObject; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; - -/** - * Created by Stardust on 2017/3/10. - */ -@Keep -public class NodeInfo { - - private List children = new ArrayList<>(); - private Rect mBoundsInScreen = new Rect(); - private Rect mBoundsInParent = new Rect(); - - public String id; - public String idHex; - public String fullId; - public String desc; - public String className; - public String packageName; - public String text; - public int depth; - public int drawingOrder; - public boolean accessibilityFocused; - public boolean checked; - public boolean clickable; - public boolean contextClickable; - public boolean dismissable; - public boolean editable; - public boolean enabled; - public boolean focusable; - public boolean longClickable; - public int row; - public int column; - public int rowCount; - public int columnCount; - public int rowSpan; - public int columnSpan; - public boolean selected; - public boolean scrollable; - public String bounds; - public boolean checkable; - public boolean focused; - public boolean visibleToUser; - public int indexInParent; - public NodeInfo parent; - - - public NodeInfo(Resources resources, UiObject node, NodeInfo parent) { - fullId = node.getViewIdResourceName(); - id = simplifyId(fullId); - desc = node.desc(); - className = node.className(); - packageName = node.packageName(); - text = node.text(); - - depth = node.depth(); - drawingOrder = node.getDrawingOrder(); - - row = node.row(); - column = node.column(); - rowCount = node.rowCount(); - columnCount = node.columnCount(); - rowSpan = node.rowSpan(); - columnSpan = node.columnSpan(); - - accessibilityFocused = node.isAccessibilityFocused(); - checked = node.isChecked(); - checkable = node.isCheckable(); - clickable = node.isClickable(); - contextClickable = node.isContextClickable(); - dismissable = node.isDismissable(); - enabled = node.isEnabled(); - editable = node.isEditable(); - focusable = node.isFocusable(); - focused = node.focused(); - longClickable = node.isLongClickable(); - selected = node.isSelected(); - scrollable = node.isScrollable(); - visibleToUser = node.visibleToUser(); - node.getBoundsInScreen(mBoundsInScreen); - node.getBoundsInParent(mBoundsInParent); - bounds = boundsToString(mBoundsInScreen); - indexInParent = node.indexInParent(); - - this.parent = parent; - if (resources != null && packageName != null && fullId != null) { - idHex = "0x" + Integer.toHexString(resources.getIdentifier(fullId, null, null)); - } - } - - private String simplifyId(String idResourceName) { - if (idResourceName == null) - return null; - int i = idResourceName.indexOf('/'); - return idResourceName.substring(i + 1); - } - - public Rect getBoundsInScreen() { - return mBoundsInScreen; - } - - - public Rect getBoundsInParent() { - return mBoundsInParent; - } - - public static String boundsToString(Rect rect) { - return rect.toString().replace('-', ',').replace(" ", "").substring(4); - } - - - static NodeInfo capture(HashMap resourcesCache, Context context, @NonNull UiObject uiObject, @Nullable NodeInfo parent) { - String pkg = uiObject.packageName(); - Resources resources = null; - if (pkg != null) { - resources = resourcesCache.get(pkg); - if (resources == null) { - try { - resources = context.getPackageManager().getResourcesForApplication(pkg); - resourcesCache.put(pkg, resources); - } catch (PackageManager.NameNotFoundException e) { - e.printStackTrace(); - } - } - } - NodeInfo nodeInfo = new NodeInfo(resources, uiObject, parent); - int childCount = uiObject.getChildCount(); - for (int i = 0; i < childCount; i++) { - UiObject child = uiObject.child(i); - if (child != null) { - nodeInfo.children.add(capture(resourcesCache, context, child, nodeInfo)); - } - } - return nodeInfo; - } - - public static NodeInfo capture(Context context, @NonNull AccessibilityNodeInfo root) { - UiObject r = UiObject.createRoot(root); - HashMap resourcesCache = new HashMap<>(); - return capture(resourcesCache, context, r, null); - } - - @NonNull - public List getChildren() { - return children; - } - - @Override - public String toString() { - return className + "{" + - "childCount=" + children.size() + - ", mBoundsInScreen=" + mBoundsInScreen + - ", mBoundsInParent=" + mBoundsInParent + - ", id='" + id + '\'' + - ", desc='" + desc + '\'' + - ", packageName='" + packageName + '\'' + - ", text='" + text + '\'' + - ", depth=" + depth + - ", drawingOrder=" + drawingOrder + - ", accessibilityFocused=" + accessibilityFocused + - ", checked=" + checked + - ", clickable=" + clickable + - ", contextClickable=" + contextClickable + - ", dismissable=" + dismissable + - ", editable=" + editable + - ", enabled=" + enabled + - ", focusable=" + focusable + - ", longClickable=" + longClickable + - ", row=" + row + - ", column=" + column + - ", rowCount=" + rowCount + - ", columnCount=" + columnCount + - ", rowSpan=" + rowSpan + - ", columnSpan=" + columnSpan + - ", selected=" + selected + - ", scrollable=" + scrollable + - ", bounds='" + bounds + '\'' + - ", checkable=" + checkable + - ", focused=" + focused + - ", visibleToUser=" + visibleToUser + - ", parent=" + parent.className + - '}'; - } -} diff --git a/automator/src/main/java/com/stardust/view/accessibility/NodeInfo.kt b/automator/src/main/java/com/stardust/view/accessibility/NodeInfo.kt new file mode 100644 index 00000000..a5b102e7 --- /dev/null +++ b/automator/src/main/java/com/stardust/view/accessibility/NodeInfo.kt @@ -0,0 +1,185 @@ +package com.stardust.view.accessibility + +import android.content.Context +import android.content.pm.PackageManager +import android.content.res.Resources +import android.graphics.Rect +import android.support.annotation.Keep +import android.view.accessibility.AccessibilityNodeInfo + +import com.stardust.automator.UiObject + +import java.util.ArrayList +import java.util.HashMap + +/** + * Created by Stardust on 2017/3/10. + */ +@Keep +class NodeInfo(resources: Resources?, node: UiObject, var parent: NodeInfo?) { + + private val children = ArrayList() + val boundsInScreen = Rect() + val boundsInParent = Rect() + + var id: String? = null + var idHex: String? = null + var fullId: String? = null + var desc: String? = null + var className: String? = null + var packageName: String? = null + var text: String + var depth: Int = 0 + var drawingOrder: Int = 0 + var accessibilityFocused: Boolean = false + var checked: Boolean = false + var clickable: Boolean = false + var contextClickable: Boolean = false + var dismissable: Boolean = false + var editable: Boolean = false + var enabled: Boolean = false + var focusable: Boolean = false + var longClickable: Boolean = false + var row: Int = 0 + var column: Int = 0 + var rowCount: Int = 0 + var columnCount: Int = 0 + var rowSpan: Int = 0 + var columnSpan: Int = 0 + var selected: Boolean = false + var scrollable: Boolean = false + var bounds: String + var checkable: Boolean = false + var focused: Boolean = false + var visibleToUser: Boolean = false + var indexInParent: Int = 0 + + + init { + fullId = node.viewIdResourceName + id = simplifyId(fullId) + desc = node.desc() + className = node.className() + packageName = node.packageName() + text = node.text() + + depth = node.depth() + drawingOrder = node.drawingOrder + + row = node.row() + column = node.column() + rowCount = node.rowCount() + columnCount = node.columnCount() + rowSpan = node.rowSpan() + columnSpan = node.columnSpan() + + accessibilityFocused = node.isAccessibilityFocused + checked = node.isChecked + checkable = node.isCheckable + clickable = node.isClickable + contextClickable = node.isContextClickable + dismissable = node.isDismissable + enabled = node.isEnabled + editable = node.isEditable + focusable = node.isFocusable + focused = node.focused() + longClickable = node.isLongClickable + selected = node.isSelected + scrollable = node.isScrollable + visibleToUser = node.visibleToUser() + node.getBoundsInScreen(boundsInScreen) + node.getBoundsInParent(boundsInParent) + bounds = boundsToString(boundsInScreen) + indexInParent = node.indexInParent() + if (resources != null && packageName != null && fullId != null) { + idHex = "0x" + Integer.toHexString(resources.getIdentifier(fullId, null, null)) + } + } + + private fun simplifyId(idResourceName: String?): String? { + if (idResourceName == null) + return null + val i = idResourceName.indexOf('/') + return idResourceName.substring(i + 1) + } + + fun getChildren(): List { + return children + } + + override fun toString(): String { + return className + "{" + + "childCount=" + children.size + + ", mBoundsInScreen=" + boundsInScreen + + ", mBoundsInParent=" + boundsInParent + + ", id='" + id + '\''.toString() + + ", desc='" + desc + '\''.toString() + + ", packageName='" + packageName + '\''.toString() + + ", text='" + text + '\''.toString() + + ", depth=" + depth + + ", drawingOrder=" + drawingOrder + + ", accessibilityFocused=" + accessibilityFocused + + ", checked=" + checked + + ", clickable=" + clickable + + ", contextClickable=" + contextClickable + + ", dismissable=" + dismissable + + ", editable=" + editable + + ", enabled=" + enabled + + ", focusable=" + focusable + + ", longClickable=" + longClickable + + ", row=" + row + + ", column=" + column + + ", rowCount=" + rowCount + + ", columnCount=" + columnCount + + ", rowSpan=" + rowSpan + + ", columnSpan=" + columnSpan + + ", selected=" + selected + + ", scrollable=" + scrollable + + ", bounds='" + bounds + '\''.toString() + + ", checkable=" + checkable + + ", focused=" + focused + + ", visibleToUser=" + visibleToUser + + ", parent=" + parent?.className + + '}'.toString() + } + + companion object { + + fun boundsToString(rect: Rect): String { + return rect.toString().replace('-', ',').replace(" ", "").substring(4) + } + + + internal fun capture(resourcesCache: HashMap, context: Context, uiObject: UiObject, parent: NodeInfo?): NodeInfo { + val pkg = uiObject.packageName() + var resources: Resources? = null + if (pkg != null) { + resources = resourcesCache[pkg] + if (resources == null) { + try { + resources = context.packageManager.getResourcesForApplication(pkg) + resourcesCache[pkg] = resources + } catch (e: PackageManager.NameNotFoundException) { + e.printStackTrace() + } + + } + } + val nodeInfo = NodeInfo(resources, uiObject, parent) + val childCount = uiObject.childCount + for (i in 0 until childCount) { + val child = uiObject.child(i) + if (child != null) { + nodeInfo.children.add(capture(resourcesCache, context, child, nodeInfo)) + } + } + return nodeInfo + } + + fun capture(context: Context, root: AccessibilityNodeInfo): NodeInfo { + val r = UiObject.createRoot(root) + val resourcesCache = HashMap() + return capture(resourcesCache, context, r, null) + } + } +} diff --git a/automator/src/main/java/com/stardust/view/accessibility/NotificationListener.java b/automator/src/main/java/com/stardust/view/accessibility/NotificationListener.java deleted file mode 100644 index f43911cc..00000000 --- a/automator/src/main/java/com/stardust/view/accessibility/NotificationListener.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.stardust.view.accessibility; - -import android.accessibilityservice.AccessibilityService; -import android.content.Context; -import android.service.notification.StatusBarNotification; -import android.support.annotation.Nullable; -import android.util.Log; -import android.view.accessibility.AccessibilityEvent; - -import com.stardust.notification.Notification; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Set; -import java.util.concurrent.CopyOnWriteArrayList; - -/** - * Created by Stardust on 2017/8/1. - */ - -public interface NotificationListener { - - - void onNotification(Notification notification); - - -} diff --git a/automator/src/main/java/com/stardust/view/accessibility/NotificationListener.kt b/automator/src/main/java/com/stardust/view/accessibility/NotificationListener.kt new file mode 100644 index 00000000..ee490b29 --- /dev/null +++ b/automator/src/main/java/com/stardust/view/accessibility/NotificationListener.kt @@ -0,0 +1,25 @@ +package com.stardust.view.accessibility + +import android.accessibilityservice.AccessibilityService +import android.content.Context +import android.service.notification.StatusBarNotification +import android.util.Log +import android.view.accessibility.AccessibilityEvent + +import com.stardust.notification.Notification + +import java.util.ArrayList +import java.util.Collections +import java.util.concurrent.CopyOnWriteArrayList + +/** + * Created by Stardust on 2017/8/1. + */ + +interface NotificationListener { + + + fun onNotification(notification: Notification) + + +} diff --git a/automator/src/main/java/com/stardust/view/accessibility/OnKeyListener.java b/automator/src/main/java/com/stardust/view/accessibility/OnKeyListener.java deleted file mode 100644 index 0453a6ef..00000000 --- a/automator/src/main/java/com/stardust/view/accessibility/OnKeyListener.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.stardust.view.accessibility; - -import android.util.Log; -import android.view.KeyEvent; -import android.view.View; - -import java.util.concurrent.CopyOnWriteArrayList; - -/** - * Created by Stardust on 2017/7/18. - */ - -public interface OnKeyListener { - - void onKeyEvent(int keyCode, KeyEvent event); - - class Observer implements OnKeyListener { - - private static final String TAG = "OnKeyListenerObserver"; - - private CopyOnWriteArrayList mOnKeyListeners = new CopyOnWriteArrayList<>(); - - @Override - public void onKeyEvent(int keyCode, KeyEvent event) { - for (OnKeyListener listener : mOnKeyListeners) { - try { - listener.onKeyEvent(keyCode, event); - } catch (Exception e) { - Log.e(TAG, "Error OnKeyEvent: " + event + " Listener: " + listener, e); - } - } - } - - public void addListener(OnKeyListener listener) { - mOnKeyListeners.add(listener); - } - - public boolean removeListener(OnKeyListener listener) { - return mOnKeyListeners.remove(listener); - } - } -} diff --git a/automator/src/main/java/com/stardust/view/accessibility/OnKeyListener.kt b/automator/src/main/java/com/stardust/view/accessibility/OnKeyListener.kt new file mode 100644 index 00000000..575a34ca --- /dev/null +++ b/automator/src/main/java/com/stardust/view/accessibility/OnKeyListener.kt @@ -0,0 +1,45 @@ +package com.stardust.view.accessibility + +import android.util.Log +import android.view.KeyEvent +import android.view.View + +import java.util.concurrent.CopyOnWriteArrayList + +/** + * Created by Stardust on 2017/7/18. + */ + +interface OnKeyListener { + + fun onKeyEvent(keyCode: Int, event: KeyEvent) + + class Observer : OnKeyListener { + + private val mOnKeyListeners = CopyOnWriteArrayList() + + override fun onKeyEvent(keyCode: Int, event: KeyEvent) { + for (listener in mOnKeyListeners) { + try { + listener.onKeyEvent(keyCode, event) + } catch (e: Exception) { + Log.e(TAG, "Error OnKeyEvent: $event Listener: $listener", e) + } + + } + } + + fun addListener(listener: OnKeyListener) { + mOnKeyListeners.add(listener) + } + + fun removeListener(listener: OnKeyListener): Boolean { + return mOnKeyListeners.remove(listener) + } + + companion object { + + private val TAG = "OnKeyListenerObserver" + } + } +} diff --git a/automator/src/test/java/com/stardust/automator/ExampleUnitTest.java b/automator/src/test/java/com/stardust/automator/ExampleUnitTest.java deleted file mode 100644 index 92a7cd0d..00000000 --- a/automator/src/test/java/com/stardust/automator/ExampleUnitTest.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.stardust.automator; - - -import org.junit.Test; - -import static org.junit.Assert.*; - -/** - * Example local unit test, which will execute on the development machine (host). - * - * @see Testing documentation - */ -public class ExampleUnitTest { - @Test - public void addition_isCorrect() throws Exception { - - } -} \ No newline at end of file diff --git a/automator/src/test/java/com/stardust/automator/ExampleUnitTest.kt b/automator/src/test/java/com/stardust/automator/ExampleUnitTest.kt new file mode 100644 index 00000000..5adca8bd --- /dev/null +++ b/automator/src/test/java/com/stardust/automator/ExampleUnitTest.kt @@ -0,0 +1,19 @@ +package com.stardust.automator + + +import org.junit.Test + +import org.junit.Assert.* + +/** + * Example local unit test, which will execute on the development machine (host). + * + * @see [Testing documentation](http://d.android.com/tools/testing) + */ +class ExampleUnitTest { + @Test + @Throws(Exception::class) + fun addition_isCorrect() { + + } +} \ No newline at end of file diff --git a/automator/src/test/java/com/stardust/automator/filter/DfsFilterTest.java b/automator/src/test/java/com/stardust/automator/filter/DfsFilterTest.java deleted file mode 100644 index 93162f3e..00000000 --- a/automator/src/test/java/com/stardust/automator/filter/DfsFilterTest.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.stardust.automator.filter; - -import com.stardust.automator.test.TestUiObject; -import com.stardust.automator.UiObject; - -import org.junit.Test; - -import java.util.List; -import java.util.Random; - -import static org.junit.Assert.*; - -/** - * Created by Stardust on 2017/5/5. - */ -public class DfsFilterTest { - - private static class RandomDfsFilter extends DfsFilter { - - private Random mRandom = new Random(); - - @Override - protected boolean isIncluded(UiObject nodeInfo) { - return mRandom.nextBoolean(); - } - } - - @Test - public void filter() throws Exception { - DfsFilter filter = new RandomDfsFilter(); - UiObject root = new TestUiObject(10); - List list = filter.filter(root); - for (UiObject uiObject : list) { - if (root != uiObject) - uiObject.recycle(); - } - System.out.println(TestUiObject.max); - assertEquals(1, TestUiObject.count); - } - -} \ No newline at end of file diff --git a/automator/src/test/java/com/stardust/automator/filter/DfsFilterTest.kt b/automator/src/test/java/com/stardust/automator/filter/DfsFilterTest.kt new file mode 100644 index 00000000..90b8d86a --- /dev/null +++ b/automator/src/test/java/com/stardust/automator/filter/DfsFilterTest.kt @@ -0,0 +1,39 @@ +package com.stardust.automator.filter + +import com.stardust.automator.test.TestUiObject +import com.stardust.automator.UiObject + +import org.junit.Test +import java.util.Random + +import org.junit.Assert.* + +/** + * Created by Stardust on 2017/5/5. + */ +class DfsFilterTest { + + private class RandomDfsFilter : DfsFilter() { + + private val mRandom = Random() + + override fun isIncluded(nodeInfo: UiObject): Boolean { + return mRandom.nextBoolean() + } + } + + @Test + @Throws(Exception::class) + fun filter() { + val filter = RandomDfsFilter() + val root = TestUiObject(10) + val list = filter.filter(root) + for (uiObject in list) { + if (root !== uiObject) + uiObject.recycle() + } + println(TestUiObject.max) + assertEquals(1, TestUiObject.count.toLong()) + } + +} \ No newline at end of file diff --git a/automator/src/test/java/com/stardust/automator/simple_action/ScrollActionTest.java b/automator/src/test/java/com/stardust/automator/simple_action/ScrollActionTest.java deleted file mode 100644 index 24613e64..00000000 --- a/automator/src/test/java/com/stardust/automator/simple_action/ScrollActionTest.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.stardust.automator.simple_action; - -import android.view.accessibility.AccessibilityNodeInfo; - -import com.stardust.automator.test.TestUiObject; -import com.stardust.automator.UiObject; - -import org.junit.Test; - -import static org.junit.Assert.*; - -/** - * Created by Stardust on 2017/5/5. - */ -public class ScrollActionTest { - @Test - public void perform() throws Exception { - ScrollAction action = new ScrollAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD, 0); - UiObject root = new TestUiObject(5); - action.perform(root); - System.out.println(TestUiObject.max); - assertEquals(1, TestUiObject.count); - } - -} \ No newline at end of file diff --git a/automator/src/test/java/com/stardust/automator/simple_action/ScrollActionTest.kt b/automator/src/test/java/com/stardust/automator/simple_action/ScrollActionTest.kt new file mode 100644 index 00000000..e23e2557 --- /dev/null +++ b/automator/src/test/java/com/stardust/automator/simple_action/ScrollActionTest.kt @@ -0,0 +1,26 @@ +package com.stardust.automator.simple_action + +import android.view.accessibility.AccessibilityNodeInfo + +import com.stardust.automator.test.TestUiObject +import com.stardust.automator.UiObject + +import org.junit.Test + +import org.junit.Assert.* + +/** + * Created by Stardust on 2017/5/5. + */ +class ScrollActionTest { + @Test + @Throws(Exception::class) + fun perform() { + val action = ScrollAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD, 0) + val root = TestUiObject(5) + action.perform(root) + println(TestUiObject.max) + assertEquals(1, TestUiObject.count.toLong()) + } + +} \ No newline at end of file diff --git a/build.gradle b/build.gradle index 254d63d6..77df33c4 100644 --- a/build.gradle +++ b/build.gradle @@ -3,12 +3,14 @@ import groovy.json.JsonSlurper // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { + ext.kotlin_version = '1.3.10' repositories { google() jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.1.4' + classpath 'com.android.tools.build:gradle:3.2.1' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } diff --git a/common/build.gradle b/common/build.gradle index 445f3e62..8d6b7ce2 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -1,4 +1,6 @@ apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-android-extensions' android { compileSdkVersion versions.compile @@ -27,6 +29,7 @@ dependencies { exclude group: 'com.android.support', module: 'support-annotations' }) testImplementation 'junit:junit:4.12' + api "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" api 'com.android.support:support-annotations:28.0.0' api 'com.github.hyb1996:settingscompat:1.1.5' } diff --git a/common/src/main/java/com/stardust/util/SparseArrayEntries.java b/common/src/main/java/com/stardust/util/SparseArrayEntries.java index 0efb3514..34325219 100644 --- a/common/src/main/java/com/stardust/util/SparseArrayEntries.java +++ b/common/src/main/java/com/stardust/util/SparseArrayEntries.java @@ -1,5 +1,6 @@ package com.stardust.util; +import android.support.annotation.NonNull; import android.util.SparseArray; /** @@ -8,13 +9,14 @@ import android.util.SparseArray; public class SparseArrayEntries { - private SparseArray mSparseArray = new SparseArray<>(); + private final SparseArray mSparseArray = new SparseArray<>(); public SparseArrayEntries entry(int key, E value) { mSparseArray.put(key, value); return this; } + @NonNull public SparseArray sparseArray() { return mSparseArray; } diff --git a/inrt/build.gradle b/inrt/build.gradle index 5b3f1ba3..49723440 100644 --- a/inrt/build.gradle +++ b/inrt/build.gradle @@ -1,4 +1,6 @@ apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-android-extensions' android { compileSdkVersion versions.compile diff --git a/inrt/src/main/java/com/stardust/auojs/inrt/autojs/AccessibilityServiceTool.java b/inrt/src/main/java/com/stardust/auojs/inrt/autojs/AccessibilityServiceTool.java index f2119adb..67ce24fa 100644 --- a/inrt/src/main/java/com/stardust/auojs/inrt/autojs/AccessibilityServiceTool.java +++ b/inrt/src/main/java/com/stardust/auojs/inrt/autojs/AccessibilityServiceTool.java @@ -39,7 +39,7 @@ public class AccessibilityServiceTool { public static boolean enableAccessibilityServiceByRootAndWaitFor(Context context, long timeOut) { if (enableAccessibilityServiceByRoot(context, com.stardust.view.accessibility.AccessibilityService.class)) { - com.stardust.view.accessibility.AccessibilityService.waitForEnabled(timeOut); + com.stardust.view.accessibility.AccessibilityService.Companion.waitForEnabled(timeOut); return true; } return false; diff --git a/inrt/src/main/java/com/stardust/auojs/inrt/autojs/AutoJs.java b/inrt/src/main/java/com/stardust/auojs/inrt/autojs/AutoJs.java index d47fede6..942c5d98 100644 --- a/inrt/src/main/java/com/stardust/auojs/inrt/autojs/AutoJs.java +++ b/inrt/src/main/java/com/stardust/auojs/inrt/autojs/AutoJs.java @@ -46,11 +46,11 @@ public class AutoJs extends com.stardust.autojs.AutoJs { @Override public void ensureAccessibilityServiceEnabled() { - if (AccessibilityService.getInstance() != null) { + if (AccessibilityService.Companion.getInstance() != null) { return; } String errorMessage = null; - if (AccessibilityServiceUtils.isAccessibilityServiceEnabled(getApplication(), AccessibilityService.class)) { + if (AccessibilityServiceUtils.INSTANCE.isAccessibilityServiceEnabled(getApplication(), AccessibilityService.class)) { errorMessage = GlobalAppContext.getString(R.string.text_auto_operate_service_enabled_but_not_running); } else { if (Pref.shouldEnableAccessibilityServiceByRoot()) { @@ -69,11 +69,11 @@ public class AutoJs extends com.stardust.autojs.AutoJs { @Override public void waitForAccessibilityServiceEnabled() { - if (AccessibilityService.getInstance() != null) { + if (AccessibilityService.Companion.getInstance() != null) { return; } String errorMessage = null; - if (AccessibilityServiceUtils.isAccessibilityServiceEnabled(getApplication(), AccessibilityService.class)) { + if (AccessibilityServiceUtils.INSTANCE.isAccessibilityServiceEnabled(getApplication(), AccessibilityService.class)) { errorMessage = GlobalAppContext.getString(R.string.text_auto_operate_service_enabled_but_not_running); } else { if (Pref.shouldEnableAccessibilityServiceByRoot()) { @@ -86,7 +86,7 @@ public class AutoJs extends com.stardust.autojs.AutoJs { } if (errorMessage != null) { AccessibilityServiceTool.goToAccessibilitySetting(); - if (!AccessibilityService.waitForEnabled(-1)) { + if (!AccessibilityService.Companion.waitForEnabled(-1)) { throw new ScriptInterruptedException(); } } diff --git a/inrt/src/main/java/com/stardust/auojs/inrt/autojs/GlobalKeyObserver.java b/inrt/src/main/java/com/stardust/auojs/inrt/autojs/GlobalKeyObserver.java index 14bff7f6..347282fa 100644 --- a/inrt/src/main/java/com/stardust/auojs/inrt/autojs/GlobalKeyObserver.java +++ b/inrt/src/main/java/com/stardust/auojs/inrt/autojs/GlobalKeyObserver.java @@ -23,7 +23,7 @@ public class GlobalKeyObserver implements OnKeyListener, ShellKeyObserver.KeyLis private boolean mVolumeUpFromShell, mVolumeUpFromAccessibility; GlobalKeyObserver() { - AccessibilityService.getStickOnKeyObserver() + AccessibilityService.Companion.getStickOnKeyObserver() .addListener(this); ShellKeyObserver observer = new ShellKeyObserver(); observer.setKeyListener(this);