Android:以编程方式打开API 24+中的Overview/Obnts屏幕

Jon*_*ise 5 android

我正在尝试在Android中打开Overview/Recents屏幕.从Android:以编程方式打开"最近的应用程序"对话框,我可以使用以下代码:

try {
    Class serviceManagerClass = Class.forName("android.os.ServiceManager");
    Method getService = serviceManagerClass.getMethod("getService", String.class);
    IBinder retbinder = (IBinder) getService.invoke(null, "statusbar");
    Class statusBarClass = Class.forName(retbinder.getInterfaceDescriptor());
    Object statusBarObject = statusBarClass.getClasses()[0]
            .getMethod("asInterface", IBinder.class).invoke(null, retbinder);
    Method toggleRecentApps = statusBarClass.getMethod("toggleRecentApps");
    toggleRecentApps.setAccessible(true);
    toggleRecentApps.invoke(statusBarObject);
} catch (InvocationTargetException| NoSuchMethodException | RemoteException | IllegalAccessException   | ClassNotFoundException e){
    handleError(e);
}
Run Code Online (Sandbox Code Playgroud)

然而,toggleRecentApps()就是在IStatusBarService不再因为牛轧糖,并且它会导致NoSuchMethodException.

是否有其他方法(不包括AccessibilityService)可用于打开Overview/Obnts屏幕?


编辑:实现IStatusBarService的类似乎是StatusBarManagerService.但是,调用statusBarObject.getClass().getCanonicalName()返回com.android.internal.statusbar.IStatusBarService.Stub.Proxy,因此通过私有字段获取IStatusBar(确实实现toggleRecentApps())mBar似乎不是一种工作方式来获取它.


编辑2:看到StatusBarManagerInternal.java是一个包含的接口void toggleRecentApps(),我试图找到它的实现,我发现StatusBarManagerService:

private final StatusBarManagerInternal mInternalService = new StatusBarManagerInternal() { ... }
Run Code Online (Sandbox Code Playgroud)

所以它是StatusManagerService中的匿名类.> :(.

但是,我也发现:

/**
 * Construct the service, add the status bar view to the window manager
 */
public StatusBarManagerService(Context context, WindowManagerService windowManager) {
    mContext = context;
    mWindowManager = windowManager;

    LocalServices.addService(StatusBarManagerInternal.class, mInternalService);
}
Run Code Online (Sandbox Code Playgroud)

因此它显然将其注册,然后在以下LocalServices内容中管理它ArrayMap:

private static final ArrayMap<Class<?>, Object> sLocalServiceObjects =
        new ArrayMap<Class<?>, Object>();
Run Code Online (Sandbox Code Playgroud)

因此,我试图访问它:

try {
    Field services = Class.forName("com.android.server.LocalServices")
            .getDeclaredField("sLocalServiceObjects");
    services.setAccessible(true);
    ArrayMap<Class<?>, Object> serviceMap = (ArrayMap<Class<?>, Object>) services.get(null);
    Set<Map.Entry<Class<?>, Object>> serviceSet = serviceMap.entrySet();

    for (Map.Entry<Class<?>, Object> serviceEntry : serviceSet) {
        if (serviceEntry.getKey().isInterface()) {
            if ("com.android.server.statusbar.StatusBarManagerInternal"
                    .equals(serviceEntry.getKey().getName())) {
                Object statusBarInternalObject = serviceEntry.getValue();
                Class statusBarInternalClass = serviceEntry.getKey();
                Method openRecents = statusBarInternalClass.getMethod("toggleRecentApps");
                openRecents.setAccessible(true);
                openRecents.invoke(statusBarInternalObject);
                return;
            }
        }
    }
} catch (Exception e) {
    handleError(e);
}
Run Code Online (Sandbox Code Playgroud)

然而:

/**
 * This class is used in a similar way as ServiceManager, except the services registered here
 * are not Binder objects and are only available in the same process.
 *
 * Once all services are converted to the SystemService interface, this class can be absorbed
 * into SystemServiceManager.
 *
 * {@hide}
 */
Run Code Online (Sandbox Code Playgroud)

唉,我必须在SystemUI过程中(或者看起来似乎)能够访问它.(实际上,它ArrayMap是空的,使我的尝试无用.)

任何关于如何从这里开始的指导将不胜感激.

Evg*_*bei 4

创建扩展自的服务AccessibilityService

class ExampleAccessService:AccessibilityService() {
    override fun onInterrupt() {
    }

    override fun onAccessibilityEvent(event: AccessibilityEvent?) {
    }

    fun doAction(){
        performGlobalAction(GLOBAL_ACTION_RECENTS)
//        performGlobalAction(GLOBAL_ACTION_BACK)
//        performGlobalAction(GLOBAL_ACTION_HOME)
//        performGlobalAction(GLOBAL_ACTION_NOTIFICATIONS)
//        performGlobalAction(GLOBAL_ACTION_POWER_DIALOG)
//        performGlobalAction(GLOBAL_ACTION_QUICK_SETTINGS)
//        performGlobalAction(GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN)
    }
}
Run Code Online (Sandbox Code Playgroud)

致电doAction()您想要采取行动的地方

添加Manifest

<application
...
    <service
        android:name=".ExampleAccessService"
        android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
        android:label="Name of servise" // it will be viewed in Settings->Accessibility->Services
        android:enabled="true"
        android:exported="false" >
        <intent-filter>
            <action android:name="android.accessibilityservice.AccessibilityService"/>
        </intent-filter>
        <meta-data
            android:name="android.accessibilityservice"
            android:resource="@xml/accessibility_service_config"/>
    </service>
...
</application>
Run Code Online (Sandbox Code Playgroud)

accessibility_service_config.xml:

<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
    android:accessibilityEventTypes="typeAllMask"
    android:accessibilityFeedbackType="feedbackAllMask"
    android:accessibilityFlags="flagDefault"
    android:canRetrieveWindowContent="false"
    android:description="your description"
    android:notificationTimeout="100"
    android:packageNames="your app package, ex: ex: com.example.android"
    android:settingsActivity="your settings activity ex: com.example.android.MainActivity" />
Run Code Online (Sandbox Code Playgroud)

有关更多信息,请参阅https://developer.android.com/guide/topics/ui/accessibility/services.html