1cddda72410c992a12db61cef26713b498e31fea4Thanh Le/*
2cddda72410c992a12db61cef26713b498e31fea4Thanh Le * Copyright (C) 2013 DroidDriver committers
3cddda72410c992a12db61cef26713b498e31fea4Thanh Le *
4cddda72410c992a12db61cef26713b498e31fea4Thanh Le * Licensed under the Apache License, Version 2.0 (the "License");
5cddda72410c992a12db61cef26713b498e31fea4Thanh Le * you may not use this file except in compliance with the License.
6cddda72410c992a12db61cef26713b498e31fea4Thanh Le * You may obtain a copy of the License at
7cddda72410c992a12db61cef26713b498e31fea4Thanh Le *
8cddda72410c992a12db61cef26713b498e31fea4Thanh Le *      http://www.apache.org/licenses/LICENSE-2.0
9cddda72410c992a12db61cef26713b498e31fea4Thanh Le *
10cddda72410c992a12db61cef26713b498e31fea4Thanh Le * Unless required by applicable law or agreed to in writing, software
11cddda72410c992a12db61cef26713b498e31fea4Thanh Le * distributed under the License is distributed on an "AS IS" BASIS,
12cddda72410c992a12db61cef26713b498e31fea4Thanh Le * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13cddda72410c992a12db61cef26713b498e31fea4Thanh Le * See the License for the specific language governing permissions and
14cddda72410c992a12db61cef26713b498e31fea4Thanh Le * limitations under the License.
15cddda72410c992a12db61cef26713b498e31fea4Thanh Le */
16cddda72410c992a12db61cef26713b498e31fea4Thanh Le
174b31201b5a2dbf8036da5a8d089a68a39cc1dc44Kevin Jinpackage io.appium.droiddriver.instrumentation;
18cddda72410c992a12db61cef26713b498e31fea4Thanh Le
19cddda72410c992a12db61cef26713b498e31fea4Thanh Leimport android.os.Build;
20cddda72410c992a12db61cef26713b498e31fea4Thanh Leimport android.view.View;
21cddda72410c992a12db61cef26713b498e31fea4Thanh Le
22cddda72410c992a12db61cef26713b498e31fea4Thanh Leimport java.lang.reflect.Field;
23cddda72410c992a12db61cef26713b498e31fea4Thanh Leimport java.lang.reflect.InvocationTargetException;
24cddda72410c992a12db61cef26713b498e31fea4Thanh Leimport java.lang.reflect.Method;
25b8fc7911443ee5666ba46e016f11284f8ffa3662Karl Blassimport java.util.Arrays;
26b8fc7911443ee5666ba46e016f11284f8ffa3662Karl Blassimport java.util.List;
27b8fc7911443ee5666ba46e016f11284f8ffa3662Karl Blass
284b31201b5a2dbf8036da5a8d089a68a39cc1dc44Kevin Jinimport io.appium.droiddriver.exceptions.DroidDriverException;
294b31201b5a2dbf8036da5a8d089a68a39cc1dc44Kevin Jin
30cddda72410c992a12db61cef26713b498e31fea4Thanh Le/**
31cddda72410c992a12db61cef26713b498e31fea4Thanh Le * Class to find the root view.
32cddda72410c992a12db61cef26713b498e31fea4Thanh Le */
33cddda72410c992a12db61cef26713b498e31fea4Thanh Lepublic class RootFinder {
34cddda72410c992a12db61cef26713b498e31fea4Thanh Le
35cddda72410c992a12db61cef26713b498e31fea4Thanh Le  private static final String VIEW_FIELD_NAME = "mViews";
36cddda72410c992a12db61cef26713b498e31fea4Thanh Le  private static final Field viewsField;
37cddda72410c992a12db61cef26713b498e31fea4Thanh Le  private static final Object windowManagerObj;
38cddda72410c992a12db61cef26713b498e31fea4Thanh Le
39cddda72410c992a12db61cef26713b498e31fea4Thanh Le  static {
4045828d52e6a2d9694eb507b5cafd3b6fcae9c33cKevin Jin    String windowManagerClassName =
4145828d52e6a2d9694eb507b5cafd3b6fcae9c33cKevin Jin        Build.VERSION.SDK_INT >= 17 ? "android.view.WindowManagerGlobal"
4245828d52e6a2d9694eb507b5cafd3b6fcae9c33cKevin Jin            : "android.view.WindowManagerImpl";
43cddda72410c992a12db61cef26713b498e31fea4Thanh Le    String instanceMethod = Build.VERSION.SDK_INT >= 17 ? "getInstance" : "getDefault";
44cddda72410c992a12db61cef26713b498e31fea4Thanh Le    try {
45cddda72410c992a12db61cef26713b498e31fea4Thanh Le      Class<?> clazz = Class.forName(windowManagerClassName);
46cddda72410c992a12db61cef26713b498e31fea4Thanh Le      Method getMethod = clazz.getMethod(instanceMethod);
47cddda72410c992a12db61cef26713b498e31fea4Thanh Le      windowManagerObj = getMethod.invoke(null);
48cddda72410c992a12db61cef26713b498e31fea4Thanh Le      viewsField = clazz.getDeclaredField(VIEW_FIELD_NAME);
49cddda72410c992a12db61cef26713b498e31fea4Thanh Le      viewsField.setAccessible(true);
50cddda72410c992a12db61cef26713b498e31fea4Thanh Le    } catch (InvocationTargetException ite) {
51cddda72410c992a12db61cef26713b498e31fea4Thanh Le      throw new DroidDriverException(String.format("could not invoke: %s on %s", instanceMethod,
52cddda72410c992a12db61cef26713b498e31fea4Thanh Le          windowManagerClassName), ite.getCause());
53cddda72410c992a12db61cef26713b498e31fea4Thanh Le    } catch (ClassNotFoundException cnfe) {
5445828d52e6a2d9694eb507b5cafd3b6fcae9c33cKevin Jin      throw new DroidDriverException(String.format("could not find class: %s",
5545828d52e6a2d9694eb507b5cafd3b6fcae9c33cKevin Jin          windowManagerClassName), cnfe);
56cddda72410c992a12db61cef26713b498e31fea4Thanh Le    } catch (NoSuchFieldException nsfe) {
57cddda72410c992a12db61cef26713b498e31fea4Thanh Le      throw new DroidDriverException(String.format("could not find field: %s on %s",
58cddda72410c992a12db61cef26713b498e31fea4Thanh Le          VIEW_FIELD_NAME, windowManagerClassName), nsfe);
59cddda72410c992a12db61cef26713b498e31fea4Thanh Le    } catch (NoSuchMethodException nsme) {
60cddda72410c992a12db61cef26713b498e31fea4Thanh Le      throw new DroidDriverException(String.format("could not find method: %s on %s",
61cddda72410c992a12db61cef26713b498e31fea4Thanh Le          instanceMethod, windowManagerClassName), nsme);
62cddda72410c992a12db61cef26713b498e31fea4Thanh Le    } catch (RuntimeException re) {
6345828d52e6a2d9694eb507b5cafd3b6fcae9c33cKevin Jin      throw new DroidDriverException(String.format(
6445828d52e6a2d9694eb507b5cafd3b6fcae9c33cKevin Jin          "reflective setup failed using obj: %s method: %s field: %s", windowManagerClassName,
6545828d52e6a2d9694eb507b5cafd3b6fcae9c33cKevin Jin          instanceMethod, VIEW_FIELD_NAME), re);
66cddda72410c992a12db61cef26713b498e31fea4Thanh Le    } catch (IllegalAccessException iae) {
6745828d52e6a2d9694eb507b5cafd3b6fcae9c33cKevin Jin      throw new DroidDriverException(String.format(
6845828d52e6a2d9694eb507b5cafd3b6fcae9c33cKevin Jin          "reflective setup failed using obj: %s method: %s field: %s", windowManagerClassName,
6945828d52e6a2d9694eb507b5cafd3b6fcae9c33cKevin Jin          instanceMethod, VIEW_FIELD_NAME), iae);
70cddda72410c992a12db61cef26713b498e31fea4Thanh Le    }
71cddda72410c992a12db61cef26713b498e31fea4Thanh Le  }
72cddda72410c992a12db61cef26713b498e31fea4Thanh Le
73cddda72410c992a12db61cef26713b498e31fea4Thanh Le  /**
74cddda72410c992a12db61cef26713b498e31fea4Thanh Le   * @return a list of {@link View}s.
75cddda72410c992a12db61cef26713b498e31fea4Thanh Le   */
76b8fc7911443ee5666ba46e016f11284f8ffa3662Karl Blass  @SuppressWarnings("unchecked")
77b8fc7911443ee5666ba46e016f11284f8ffa3662Karl Blass  public static List<View> getRootViews() {
78b8fc7911443ee5666ba46e016f11284f8ffa3662Karl Blass    List<View> views = null;
79cddda72410c992a12db61cef26713b498e31fea4Thanh Le
80cddda72410c992a12db61cef26713b498e31fea4Thanh Le    try {
81b8fc7911443ee5666ba46e016f11284f8ffa3662Karl Blass      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
82b8fc7911443ee5666ba46e016f11284f8ffa3662Karl Blass        views = (List<View>) viewsField.get(windowManagerObj);
83b8fc7911443ee5666ba46e016f11284f8ffa3662Karl Blass      } else {
84b8fc7911443ee5666ba46e016f11284f8ffa3662Karl Blass        views = Arrays.asList((View[]) viewsField.get(windowManagerObj));
85b8fc7911443ee5666ba46e016f11284f8ffa3662Karl Blass      }
86cddda72410c992a12db61cef26713b498e31fea4Thanh Le      return views;
87cddda72410c992a12db61cef26713b498e31fea4Thanh Le    } catch (RuntimeException re) {
88cddda72410c992a12db61cef26713b498e31fea4Thanh Le      throw new DroidDriverException(String.format("Reflective access to %s on %s failed.",
89cddda72410c992a12db61cef26713b498e31fea4Thanh Le          viewsField, windowManagerObj), re);
90cddda72410c992a12db61cef26713b498e31fea4Thanh Le    } catch (IllegalAccessException iae) {
91cddda72410c992a12db61cef26713b498e31fea4Thanh Le      throw new DroidDriverException(String.format("Reflective access to %s on %s failed.",
92cddda72410c992a12db61cef26713b498e31fea4Thanh Le          viewsField, windowManagerObj), iae);
93cddda72410c992a12db61cef26713b498e31fea4Thanh Le    }
94cddda72410c992a12db61cef26713b498e31fea4Thanh Le  }
95cddda72410c992a12db61cef26713b498e31fea4Thanh Le}
96