我正在尝试在Android中打开Overview / Recents屏幕。从Android: Programmatically open "Recent Apps" dialog开始,我可以使用以下代码:
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);
}
但是,自从Nougat以来toggleRecentApps()
为no longer in IStatusBarService,它会导致NoSuchMethodException。
是否有其他方法(不包括AccessibilityService)可用于打开概述/最近的屏幕?
编辑:实现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() { ... }
所以它是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);
}
所以它显然在LocalServices
中注册了它,而后者又在ArrayMap
中管理它:
private static final ArrayMap<Class<?>, Object> sLocalServiceObjects =
new ArrayMap<Class<?>, Object>();
因此,我试图访问它:
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);
}
然而:
/**
* 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}
*/
唉,我必须在SystemUI过程中(或者看起来似乎)能够访问它。 (实际上,ArrayMap
为空,导致我的尝试无用。)
任何关于如何从这里开始的指导将不胜感激。
答案 0 :(得分:0)
创建从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)
}
}
致电您需要采取行动的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>
<强> 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" />
了解更多信息,请查看https://developer.android.com/guide/topics/ui/accessibility/services.html