Home | History | Annotate | Download | only in instrumentation
      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 
     17 package io.appium.droiddriver.instrumentation;
     18 
     19 import android.os.Build;
     20 import android.view.View;
     21 
     22 import java.lang.reflect.Field;
     23 import java.lang.reflect.InvocationTargetException;
     24 import java.lang.reflect.Method;
     25 import java.util.Arrays;
     26 import java.util.List;
     27 
     28 import io.appium.droiddriver.exceptions.DroidDriverException;
     29 
     30 /**
     31  * Class to find the root view.
     32  */
     33 public class RootFinder {
     34 
     35   private static final String VIEW_FIELD_NAME = "mViews";
     36   private static final Field viewsField;
     37   private static final Object windowManagerObj;
     38 
     39   static {
     40     String windowManagerClassName =
     41         Build.VERSION.SDK_INT >= 17 ? "android.view.WindowManagerGlobal"
     42             : "android.view.WindowManagerImpl";
     43     String instanceMethod = Build.VERSION.SDK_INT >= 17 ? "getInstance" : "getDefault";
     44     try {
     45       Class<?> clazz = Class.forName(windowManagerClassName);
     46       Method getMethod = clazz.getMethod(instanceMethod);
     47       windowManagerObj = getMethod.invoke(null);
     48       viewsField = clazz.getDeclaredField(VIEW_FIELD_NAME);
     49       viewsField.setAccessible(true);
     50     } catch (InvocationTargetException ite) {
     51       throw new DroidDriverException(String.format("could not invoke: %s on %s", instanceMethod,
     52           windowManagerClassName), ite.getCause());
     53     } catch (ClassNotFoundException cnfe) {
     54       throw new DroidDriverException(String.format("could not find class: %s",
     55           windowManagerClassName), cnfe);
     56     } catch (NoSuchFieldException nsfe) {
     57       throw new DroidDriverException(String.format("could not find field: %s on %s",
     58           VIEW_FIELD_NAME, windowManagerClassName), nsfe);
     59     } catch (NoSuchMethodException nsme) {
     60       throw new DroidDriverException(String.format("could not find method: %s on %s",
     61           instanceMethod, windowManagerClassName), nsme);
     62     } catch (RuntimeException re) {
     63       throw new DroidDriverException(String.format(
     64           "reflective setup failed using obj: %s method: %s field: %s", windowManagerClassName,
     65           instanceMethod, VIEW_FIELD_NAME), re);
     66     } catch (IllegalAccessException iae) {
     67       throw new DroidDriverException(String.format(
     68           "reflective setup failed using obj: %s method: %s field: %s", windowManagerClassName,
     69           instanceMethod, VIEW_FIELD_NAME), iae);
     70     }
     71   }
     72 
     73   /**
     74    * @return a list of {@link View}s.
     75    */
     76   @SuppressWarnings("unchecked")
     77   public static List<View> getRootViews() {
     78     List<View> views = null;
     79 
     80     try {
     81       if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
     82         views = (List<View>) viewsField.get(windowManagerObj);
     83       } else {
     84         views = Arrays.asList((View[]) viewsField.get(windowManagerObj));
     85       }
     86       return views;
     87     } catch (RuntimeException re) {
     88       throw new DroidDriverException(String.format("Reflective access to %s on %s failed.",
     89           viewsField, windowManagerObj), re);
     90     } catch (IllegalAccessException iae) {
     91       throw new DroidDriverException(String.format("Reflective access to %s on %s failed.",
     92           viewsField, windowManagerObj), iae);
     93     }
     94   }
     95 }
     96