Есть ли способ программно найти все окна в данном приложении?
можно ли программно перечислить все android.view.Window
S или виды декора в приложении?
Dialogs
например, оба откроются в новом Window
, отдельно от главного окна действия. Я могу найти их через Dialog.getWindow()
но я не уверен, как я бы это сделал со встроенными компонентами, такими как всплывающее меню активности.
есть ли какой-либо способ, от Application
, Context
или WindowManager
или что-то еще, чтобы перечислить окна, связанные с мое приложение?
Я вижу все окна моего приложения с adb dumpsys window
, но я ищу способ сделать это в моем приложении, не требуя корень.
4 ответов
Я нашел способ сделать это через отражение на @hidden WindowManagerGlobal
. По крайней мере, пока я знаю, что это работает для 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();
}
}
выход:
найден корневой вид: com.образец.paintsample / com.образец.paintsample.PaintSample / android.вид.ViewRootImpl@41deeff0: com.андроид.внутренний.политика.impl.PhoneWindow$DecorView{41dcc278 В. Е..... Р....... 0,0-768,1184}
найден корневой вид: PopupWindow: 42887380 / android.вид.ViewRootImpl@42891820: андроид.штучка.PopupWindow$PopupViewContainer{42891450 В. Е..... ........ 0,0-424,618}
Баунти все еще для захватов, конечно, для тех, кто может найти лучший способ :)
Я не совсем уверен, что это отвечает на фактический вопрос, но это лучший способ получить все корневые представления, как предложено в принятом ответе.
Как уже упоминалось, мне также удалось выполнить это только с помощью отражения, за исключением того, что этот код поддерживает все версии из API-интерфейс 14 и выше (я не проверял ниже):
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>();
}
на Hierarchyviewer инструмент, который поставляется с SDK, стоит своего веса в золоте.
вы можете использовать @hidden APIs напрямую, без использования отражения, получая доступ к файлам классов и добавляя их в свой android.jar в Android SDK. Вот как: https://devmaze.wordpress.com/2011/01/18/using-com-android-internal-part-1-introduction/
и источник для android.банку для конкретной версии android (19,21,22,23,24) можно схватить здесь: https://github.com/anggrayudi/android-hidden-api
таким образом, вы можете использовать Класс WindowManagerGlobal напрямую, чтобы получить всю корневую вид вроде
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*/
}
}
выход:
корневой вид: com.образец.paintsample / com.образец.paintsample.PaintSample / android.вид.ViewRootImpl@41deeff0: com.андроид.внутренний.политика.impl.PhoneWindow$DecorView{41dcc278 В. Е..... Р....... 0,0-768,1184}
корневой вид: PopupWindow:42887380 / android.вид.ViewRootImpl@42891820: android.штучка.PopupWindow$PopupViewContainer{42891450 В. Е..... ........ 0,0-424,618}