1/*
2 * Copyright (C) 2013 DroidDriver committers
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.google.android.droiddriver.instrumentation;
18
19import android.os.Build;
20import android.view.View;
21
22import com.google.android.droiddriver.exceptions.DroidDriverException;
23
24import java.lang.reflect.Field;
25import java.lang.reflect.InvocationTargetException;
26import java.lang.reflect.Method;
27
28/**
29 * Class to find the root view.
30 */
31public class RootFinder {
32
33  private static final String VIEW_FIELD_NAME = "mViews";
34  private static final Field viewsField;
35  private static final Object windowManagerObj;
36
37  static {
38    String windowManagerClassName =
39        Build.VERSION.SDK_INT >= 17 ? "android.view.WindowManagerGlobal"
40            : "android.view.WindowManagerImpl";
41    String instanceMethod = Build.VERSION.SDK_INT >= 17 ? "getInstance" : "getDefault";
42    try {
43      Class<?> clazz = Class.forName(windowManagerClassName);
44      Method getMethod = clazz.getMethod(instanceMethod);
45      windowManagerObj = getMethod.invoke(null);
46      viewsField = clazz.getDeclaredField(VIEW_FIELD_NAME);
47      viewsField.setAccessible(true);
48    } catch (InvocationTargetException ite) {
49      throw new DroidDriverException(String.format("could not invoke: %s on %s", instanceMethod,
50          windowManagerClassName), ite.getCause());
51    } catch (ClassNotFoundException cnfe) {
52      throw new DroidDriverException(String.format("could not find class: %s",
53          windowManagerClassName), cnfe);
54    } catch (NoSuchFieldException nsfe) {
55      throw new DroidDriverException(String.format("could not find field: %s on %s",
56          VIEW_FIELD_NAME, windowManagerClassName), nsfe);
57    } catch (NoSuchMethodException nsme) {
58      throw new DroidDriverException(String.format("could not find method: %s on %s",
59          instanceMethod, windowManagerClassName), nsme);
60    } catch (RuntimeException re) {
61      throw new DroidDriverException(String.format(
62          "reflective setup failed using obj: %s method: %s field: %s", windowManagerClassName,
63          instanceMethod, VIEW_FIELD_NAME), re);
64    } catch (IllegalAccessException iae) {
65      throw new DroidDriverException(String.format(
66          "reflective setup failed using obj: %s method: %s field: %s", windowManagerClassName,
67          instanceMethod, VIEW_FIELD_NAME), iae);
68    }
69  }
70
71  /**
72   * @return a list of {@link View}s.
73   */
74  public static View[] getRootViews() {
75    View[] views = null;
76
77    try {
78      views = (View[]) viewsField.get(windowManagerObj);
79      return views;
80    } catch (RuntimeException re) {
81      throw new DroidDriverException(String.format("Reflective access to %s on %s failed.",
82          viewsField, windowManagerObj), re);
83    } catch (IllegalAccessException iae) {
84      throw new DroidDriverException(String.format("Reflective access to %s on %s failed.",
85          viewsField, windowManagerObj), iae);
86    }
87  }
88}
89