新增 auto.setFlags("useShell"),可以使用shell获取当前活动和当前包名,更加准确

This commit is contained in:
hyb1996 2018-12-17 23:06:46 +08:00
parent ff0b215115
commit 2312e610bf
8 changed files with 212 additions and 101 deletions

View File

@ -64,10 +64,19 @@ android {
productFlavors {
common {
buildConfigField "String", "CHANNEL", '"common"'
ndk {
abiFilters "armeabi-v7a"
}
}
coolapk {
buildConfigField "String", "CHANNEL", '"coolapk"'
}
x86 {
buildConfigField "String", "CHANNEL", '"common"'
ndk {
abiFilters "x86"
}
}
}
}

View File

@ -111,7 +111,8 @@ module.exports = function(runtime, global){
const flagsMap = {
"findOnUiThread": 1,
"useUsageStats": 2
"useUsageStats": 2,
"useShell": 4
};
var auto = function(mode){
@ -163,7 +164,10 @@ module.exports = function(runtime, global){
auto.getRoot = function(){
var root = runtime.accessibilityBridge.getRootInCurrentWindow();
return com.stardust.automator.UiObject.createRoot(root);
if(root == null){
return null;
}
return com.stardust.automator.UiObject.Companion.createRoot(root);
}
auto.setWindowFilter = function(filter){

View File

@ -30,7 +30,7 @@ import com.stardust.autojs.script.JavaScriptSource;
import com.stardust.util.ResourceMonitor;
import com.stardust.util.ScreenMetrics;
import com.stardust.util.UiHandler;
import com.stardust.view.accessibility.AccessibilityInfoProvider;
import com.stardust.autojs.core.activity.ActivityInfoProvider;
import com.stardust.view.accessibility.AccessibilityNotificationObserver;
import com.stardust.view.accessibility.AccessibilityService;
import com.stardust.view.accessibility.LayoutInspector;
@ -54,7 +54,7 @@ public abstract class AutoJs {
private final Application mApplication;
private final UiHandler mUiHandler;
private final AppUtils mAppUtils;
private final AccessibilityInfoProvider mAccessibilityInfoProvider;
private final ActivityInfoProvider mActivityInfoProvider;
private final ScreenCaptureRequester mScreenCaptureRequester = new ScreenCaptureRequesterImpl();
private final ScriptEngineService mScriptEngineService;
private final GlobalConsole mGlobalConsole;
@ -68,7 +68,7 @@ public abstract class AutoJs {
mAppUtils = createAppUtils(mContext);
mGlobalConsole = createGlobalConsole();
mNotificationObserver = new AccessibilityNotificationObserver(mContext);
mAccessibilityInfoProvider = new AccessibilityInfoProvider(mContext);
mActivityInfoProvider = new ActivityInfoProvider(mContext);
mScriptEngineService = buildScriptEngineService();
ScriptEngineService.setInstance(mScriptEngineService);
init();
@ -166,7 +166,7 @@ public abstract class AutoJs {
private void addAccessibilityServiceDelegates() {
AccessibilityService.Companion.addDelegate(100, mAccessibilityInfoProvider);
AccessibilityService.Companion.addDelegate(100, mActivityInfoProvider);
AccessibilityService.Companion.addDelegate(200, mNotificationObserver);
AccessibilityService.Companion.addDelegate(300, mAccessibilityActionRecorder);
}
@ -195,8 +195,8 @@ public abstract class AutoJs {
return mScriptEngineService;
}
public AccessibilityInfoProvider getInfoProvider() {
return mAccessibilityInfoProvider;
public ActivityInfoProvider getInfoProvider() {
return mActivityInfoProvider;
}
@ -229,8 +229,8 @@ public abstract class AutoJs {
}
@Override
public AccessibilityInfoProvider getInfoProvider() {
return mAccessibilityInfoProvider;
public ActivityInfoProvider getInfoProvider() {
return mActivityInfoProvider;
}
@Override

View File

@ -1,5 +1,6 @@
package com.stardust.autojs.core.accessibility;
import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.content.Context;
import android.os.Build;
@ -14,7 +15,7 @@ import com.stardust.app.AppOpsKt;
import com.stardust.autojs.runtime.accessibility.AccessibilityConfig;
import com.stardust.util.IntentUtil;
import com.stardust.util.UiHandler;
import com.stardust.view.accessibility.AccessibilityInfoProvider;
import com.stardust.autojs.core.activity.ActivityInfoProvider;
import com.stardust.view.accessibility.AccessibilityNotificationObserver;
import com.stardust.view.accessibility.AccessibilityService;
@ -34,6 +35,7 @@ public abstract class AccessibilityBridge {
public static final int FLAG_FIND_ON_UI_THREAD = 1;
public static final int FLAG_USE_USAGE_STATS = 2;
public static final int FLAG_USE_SHELL = 4;
private int mMode = MODE_NORMAL;
private int mFlags = 0;
@ -63,6 +65,7 @@ public abstract class AccessibilityBridge {
@Nullable
public AccessibilityNodeInfo getRootInCurrentWindow() {
AccessibilityService service = getService();
if (service == null)
return null;
if (mWindowFilter != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
@ -89,7 +92,7 @@ public abstract class AccessibilityBridge {
mWindowFilter = windowFilter;
}
public abstract AccessibilityInfoProvider getInfoProvider();
public abstract ActivityInfoProvider getInfoProvider();
public void setMode(int mode) {
mMode = mode;
@ -108,6 +111,7 @@ public abstract class AccessibilityBridge {
}
}
getInfoProvider().setUseUsageStats((mFlags & FLAG_USE_USAGE_STATS) != 0);
getInfoProvider().setUseShell((mFlags & FLAG_USE_SHELL) != 0);
}
@NonNull

View File

@ -0,0 +1,181 @@
package com.stardust.autojs.core.activity
import android.accessibilityservice.AccessibilityService
import android.app.AppOpsManager
import android.app.usage.UsageStatsManager
import android.content.ComponentName
import android.content.Context
import android.content.pm.PackageManager
import android.os.Build
import android.util.Log
import android.view.accessibility.AccessibilityEvent
import androidx.annotation.RequiresApi
import com.stardust.app.isOpPermissionGranted
import com.stardust.autojs.core.util.Shell
import com.stardust.view.accessibility.AccessibilityDelegate
import java.util.regex.Pattern
/**
* Created by Stardust on 2017/3/9.
*/
class ActivityInfoProvider(private val context: Context) : AccessibilityDelegate {
private val mPackageManager: PackageManager = context.packageManager
@Volatile
private var mLatestPackage: String = ""
@Volatile
private var mLatestActivity: String = ""
private var mLatestComponentFromShell: ComponentName? = null
private var mShell: Shell? = null
private var mUseShell = false
val latestPackage: String
get() {
val compFromShell = mLatestComponentFromShell
if (useShell && compFromShell != null) {
return compFromShell.packageName
}
if (useUsageStats && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
mLatestPackage = getLatestPackageByUsageStats()
}
return mLatestPackage
}
val latestActivity: String
get() {
val compFromShell = mLatestComponentFromShell
if (useShell && compFromShell != null) {
return compFromShell.className
}
return mLatestActivity
}
var useUsageStats: Boolean = false
var useShell: Boolean
get() = mUseShell
set(value) {
if (value) {
mShell.let {
if (it == null) {
mShell = createShell(200)
}
}
} else {
mShell?.exit()
mShell = null
}
mUseShell = value
}
override val eventTypes: Set<Int>?
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
}
fun getLatestPackageByUsageStatsIfGranted(): String {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1 && context.isOpPermissionGranted(AppOpsManager.OPSTR_GET_USAGE_STATS)) {
return getLatestPackageByUsageStats()
}
return mLatestPackage
}
private fun setLatestComponentFromShellOutput(output: String) {
val matcher = WINDOW_PATTERN.matcher(output)
if (!matcher.find() || matcher.groupCount() < 1) {
Log.w(LOG_TAG, "invalid format: $output")
return
}
val latestPackage = matcher.group(1)
if (latestPackage.contains(":")) {
return
}
val latestActivity = if (matcher.groupCount() >= 2) {
matcher.group(2).orEmpty()
} else {
""
}
Log.d(LOG_TAG, "setLatestComponent: output = $output, comp = $latestPackage/$latestActivity")
mLatestComponentFromShell = ComponentName(latestPackage, latestActivity)
}
private fun createShell(dumpInterval: Int): Shell {
val shell = Shell(true)
shell.setCallback(object : Shell.Callback {
override fun onOutput(str: String) {
}
override fun onNewLine(line: String) {
setLatestComponentFromShellOutput(line)
}
override fun onInitialized() {
}
override fun onInterrupted(e: InterruptedException) {
}
})
shell.exec(DUMP_WINDOW_COMMAND.format(dumpInterval))
return shell
}
@RequiresApi(Build.VERSION_CODES.LOLLIPOP_MR1)
fun getLatestPackageByUsageStats(): String {
val usageStatsManager = context.getSystemService(Context.USAGE_STATS_SERVICE) as UsageStatsManager
val current = System.currentTimeMillis()
val usageStats = usageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_BEST, current - 60 * 60 * 1000, current)
return if (usageStats.isEmpty()) {
mLatestPackage
} else {
usageStats.sortBy {
it.lastTimeStamp
}
usageStats.last().packageName
}
}
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)
mLatestActivity = mPackageManager.getActivityInfo(componentName, PackageManager.MATCH_DEFAULT_ONLY).name
} catch (ignored: PackageManager.NameNotFoundException) {
return
}
mLatestPackage = latestPackage.toString()
}
companion object {
private val WINDOW_PATTERN = Pattern.compile("Window\\{\\S+\\s\\S+\\s([^\\/]+)\\/?([^}]+)?\\}")
private val DUMP_WINDOW_COMMAND = """
oldActivity=""
currentActivity=`dumpsys window windows | grep -E 'mCurrentFocus'`
while true
do
if [[ ${'$'}oldActivity != ${'$'}currentActivity && ${'$'}currentActivity != *"=null"* ]]; then
echo ${'$'}currentActivity
oldActivity=${'$'}currentActivity
fi
currentActivity=`dumpsys window windows | grep -E 'mCurrentFocus'`
done
""".trimIndent()
private const val LOG_TAG = "ActivityInfoProvider"
}
}

View File

@ -47,7 +47,7 @@ import com.stardust.util.ScreenMetrics;
import com.stardust.util.SdkVersionUtil;
import com.stardust.util.Supplier;
import com.stardust.util.UiHandler;
import com.stardust.view.accessibility.AccessibilityInfoProvider;
import com.stardust.autojs.core.activity.ActivityInfoProvider;
import org.mozilla.javascript.ContextFactory;
import org.mozilla.javascript.RhinoException;
@ -140,7 +140,7 @@ public class ScriptRuntime {
public final SimpleActionAutomator automator;
@ScriptVariable
public final AccessibilityInfoProvider info;
public final ActivityInfoProvider info;
@ScriptVariable
public final UI ui;

View File

@ -1,87 +0,0 @@
package com.stardust.view.accessibility
import android.accessibilityservice.AccessibilityService
import android.app.AppOpsManager
import android.app.usage.UsageStatsManager
import android.content.ComponentName
import android.content.Context
import android.content.pm.PackageManager
import android.os.Build
import android.view.accessibility.AccessibilityEvent
import androidx.annotation.RequiresApi
import com.stardust.app.isOpPermissionGranted
/**
* Created by Stardust on 2017/3/9.
*/
class AccessibilityInfoProvider(private val context: Context) : AccessibilityDelegate {
private val mPackageManager: PackageManager = context.packageManager
@Volatile
private var mLatestPackage: String = ""
val latestPackage: String
get() {
if (useUsageStats && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
mLatestPackage = getLatestPackageByUsageStats()
}
return mLatestPackage
}
@Volatile
var latestActivity = ""
private set
var useUsageStats: Boolean = false
override val eventTypes: Set<Int>?
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
}
fun getLatestPackageByUsageStatsIfGranted(): String {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1 && context.isOpPermissionGranted(AppOpsManager.OPSTR_GET_USAGE_STATS)) {
return getLatestPackageByUsageStats()
}
return mLatestPackage
}
@RequiresApi(Build.VERSION_CODES.LOLLIPOP_MR1)
fun getLatestPackageByUsageStats(): String {
val usageStatsManager = context.getSystemService(Context.USAGE_STATS_SERVICE) as UsageStatsManager
val current = System.currentTimeMillis()
val usageStats = usageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_BEST, current - 60 * 60 * 1000, current)
return if (usageStats.isEmpty()) {
mLatestPackage
} else {
usageStats.sortBy {
it.lastTimeStamp
}
usageStats.last().packageName
}
}
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
}
mLatestPackage = latestPackage.toString()
}
}