2017-01-05 11 views
3

AndroidのOverview/Recents画面を開こうとしています。 Android: Programmatically open "Recent Apps" dialogから、私は次のコードを使用することができます:Android:プログラムで開いているAPIの概要/ Recents画面24+

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); 
} 

をしかし、toggleRecentApps()はヌガー以来no longer in IStatusBarServiceであり、それはないNoSuchMethodExceptionが発生します。

Overview/Recents画面を開くために使用できる他の方法(AccessibilityServiceを除く)はありますか?


EDIT:IStatusBarServiceはStatusBarManagerServiceであるように思わ実装するクラスです。ただし、statusBarObject.getClass().getCanonicalName()を呼び出すとcom.android.internal.statusbar.IStatusBarService.Stub.Proxyが返されるため、IStatusBartoggleRecentApps()が実装されています)をプライベートフィールドmBarで取得することは効果的ではありません。


EDIT 2

private final StatusBarManagerInternal mInternalService = new StatusBarManagerInternal() { ... } 

だから、匿名クラスの中にあります:StatusBarManagerInternal.javaはvoid toggleRecentApps()が含まれているインターフェースであることを見て、私は私がStatusBarManagerServiceで見つかったその実装を、見つけることを試みました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); 
} 

だから、明らかに順番にArrayMapでそれを管理する、LocalServicesに登録する:

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は空であり、私の試行は役に立たない。)

ここから進める方法についてのガイダンスはありがたい。

+1

のAPIが変更することができますリフレクション経由で呼び出されるメソッドの問題です。 – rekire

+0

デバイスメーカやカスタムROM開発者は、Androidの内部構造を適切に修正することができますので、その方法は必ずしも任意のデバイスで利用できるわけではありません。 – CommonsWare

+0

@CommonsWareは真だが、少なくとも私は在庫のAndroidで動作する必要があります。 –

答えて

0

サービスを作成しますがAccessibilityServiceから延長:

<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を:あなたは、アクション

Manifestに追加したい

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()。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

関連する問題