2013-10-29 6 views
14

Ist es möglich, alle android.view.Window s oder Dekoransichten innerhalb einer Anwendung programmgesteuert aufzuzählen?Gibt es eine Möglichkeit, programmgesteuert alle Windows innerhalb einer bestimmten Anwendung zu finden?

Dialogs zum Beispiel wird beide in einem neuen Window, getrennt von der Hauptaktivität Fenster geöffnet. Ich kann sie über Dialog.getWindow() finden, aber ich bin nicht sicher, wie ich dies mit einer eingebauten Komponenten wie dem Popup des Aktivitätsmenüs tun würde.

Gibt es eine Möglichkeit, aus einer Application, Context, oder der WindowManager oder etwas anderes, die Windows mit meiner App zu enumerieren?

Ich kann alle meine Anwendungsfenster mit adb dumpsys window sehen, aber ich bin auf der Suche nach einer Möglichkeit, dies innerhalb meiner Anwendung ohne root zu tun.

+0

Das Fenster für das Aktivitätsmenü-Popup wäre das gleiche wie das der Aktivität, würde Activity.getWindow() nicht für Sie funktionieren? – kassim

+0

Leider nein. Ich führe das android FingerPaint-Beispiel (auf 4.3) und nachdem ich auf die drei-Punkt-Menü-Taste tippen, und ich kann im Monitor sehen, dass das Popup in einem eigenen Fenster ist. Ich kann auch „adb shell dumpsys Fenster Token“ und sehen laufen, dass die Farbe App zwei Fenster mit ihm verbunden hat in der Tat: allAppWindows = [Fenster {418f9ce8 u0 com.example.paintsample/com.example.paintsample.PaintSample} , Fenster {41a06d08 u0 PopupWindow: 41ac65a0}] Gleiches gilt für Dialoge. –

+0

Nur neugierig, warum brauchen Sie diese Informationen, oder vielmehr, was werden Sie damit machen, sobald Sie es haben? – Josh

Antwort

15

Ich habe einen Weg gefunden, es über Reflexion auf dem @hidden WindowManagerGlobal zu tun. Zumindest weiß ich das funktioniert für Android-18.

private void logRootViews() { 
    try { 
     Class wmgClass = Class.forName("android.view.WindowManagerGlobal");       
     Object wmgInstnace = wmgClass.getMethod("getInstance").invoke(null, (Object[])null); 

     Method getViewRootNames = wmgClass.getMethod("getViewRootNames"); 
     Method getRootView = wmgClass.getMethod("getRootView", String.class); 
     String[] rootViewNames = (String[])getViewRootNames.invoke(wmgInstnace, (Object[])null); 

     for(String viewName : rootViewNames) { 
      View rootView = (View)getRootView.invoke(wmgInstnace, viewName); 
      Log.i(TAG, "Found root view: " + viewName + ": " + rootView); 
     } 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
} 

Ausgang:

gefunden Stammansicht: com.example.paintsample/com.example.paintsample.PaintSample/[email protected]: com.android.internal.policy .impl.PhoneWindow $ DecorView {41dcc278 VE .... R ....... 0,0-768,1184}

gefunden Stammansicht: PopupWindow: 42887380/[email protected] : android.widget.PopupWindow $ Popu pViewContainer {42891450 VE .... ........ 0,0-424,618}

Bounty ist noch zu vergeben natürlich für jeden, der einen besseren Weg finden :)

3

Das mit dem SDK gelieferte Tool Hierarchyviewer ist Gold wert.

+0

Es ist, aber ich suchte nach einer Möglichkeit, es programmgesteuert zu tun (die ich habe, obwohl ich eine versteckte Klasse berühren muss, um es zu tun). Wird die Frage ein wenig beheben, um das klarer zu machen. –

+0

Oh, es ist okay - ich dachte nicht, dass Sie adb Dumpsys auf dem Gerät selbst verwenden. – Pedantic

6

Ich bin mir nicht ganz sicher, ob dies die eigentliche Frage beantwortet, aber es ist ein besserer Weg, alle Wurzelansichten zu erhalten, wie in der akzeptierten Antwort vorgeschlagen.

Wie erwähnt, habe ich es geschafft, auch diese nur mit Reflexion zu erreichen, es sei denn dieser Code Alle Versionen von API 14 und höher unterstützt (ich habe unten nicht geprüft):

public static List<View> getWindowManagerViews() { 
    try { 

     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH && 
       Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) { 

      // get the list from WindowManagerImpl.mViews 
      Class wmiClass = Class.forName("android.view.WindowManagerImpl"); 
      Object wmiInstance = wmiClass.getMethod("getDefault").invoke(null); 

      return viewsFromWM(wmiClass, wmiInstance); 

     } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { 

      // get the list from WindowManagerGlobal.mViews 
      Class wmgClass = Class.forName("android.view.WindowManagerGlobal"); 
      Object wmgInstance = wmgClass.getMethod("getInstance").invoke(null); 

      return viewsFromWM(wmgClass, wmgInstance); 
     } 

    } catch (Exception e) { 
     e.printStackTrace(); 
    } 

    return new ArrayList<View>(); 
} 

private static List<View> viewsFromWM(Class wmClass, Object wmInstance) throws Exception { 

    Field viewsField = wmClass.getDeclaredField("mViews"); 
    viewsField.setAccessible(true); 
    Object views = viewsField.get(wmInstance); 

    if (views instanceof List) { 
     return (List<View>) viewsField.get(wmInstance); 
    } else if (views instanceof View[]) { 
     return Arrays.asList((View[])viewsField.get(wmInstance)); 
    } 

    return new ArrayList<View>(); 
} 
+1

Dies ist die beste Lösung hier !! – refaelos

0

Sie Sie können @hidden-APIs direkt verwenden, ohne Reflektionen zu verwenden, indem Sie auf die Klassendateien zugreifen und sie dann zu Ihrer android.jar im Android SDK hinzufügen. Hier ist wie: https://devmaze.wordpress.com/2011/01/18/using-com-android-internal-part-1-introduction/

Und die Quelle für den Android.jar für bestimmte Android-Version (19,21,22,23,24) kann hier gepackt werden: https://github.com/anggrayudi/android-hidden-api

Sie die WindowManagerGlobal Klasse direkt wie alle Wurzeln Ansichten erhalten verwenden können, also dann,

private void logRootViews() { 
    WindowManagerGlobal windowManagerGlobal = WindowManagerGlobal.getInstance(); 
    String[] rootViewNames = windowManagerGlobal.getViewRootNames(); 

    for (String viewName : rootViewNames) { 
     View rootView = windowManagerGlobal.getRootView(viewName); 
     Log.i("", "Root view is: " + viewName + ": " + rootView); 
     /*do what you want with the rootView*/ 
    } 
} 

Ausgang:

Root-Ansicht ist: com.example.paintsample/com.example.paintsample.PaintSample/[email protected]: com.android.internal.policy.impl.PhoneWindow $ DecorView {41dcc278 VE .... R ....... 0,0-768,1184}

Root-Ansicht ist: PopupWindow: 42887380/[email protected]: android.widget.PopupWindow $ PopupViewContainer {42891450 VE .... ........ 0,0-424,618}

Verwandte Themen