• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
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 package com.android.contacts;
17 
18 import android.app.Activity;
19 import android.app.Instrumentation;
20 import android.content.Context;
21 import android.os.Bundle;
22 import android.os.Debug;
23 import android.support.test.InstrumentationRegistry;
24 import android.util.Log;
25 
26 import java.lang.reflect.InvocationTargetException;
27 import java.lang.reflect.Method;
28 
29 /**
30  * Runs a single static method specified via the arguments.
31  *
32  * Useful for manipulating the app state during manual testing. If the class argument is omitted
33  * this class will attempt to invoke a method in
34  * {@link com.android.contacts.tests.AdbHelpers}
35  *
36  * Valid signatures: void f(Context, Bundle), void f(Context), void f()
37  *
38  * Example usage:
39  * $ adb shell am instrument -e class com.android.contacts.Foo -e method bar -e someArg someValue\
40  *   -w com.google.android.contacts.tests/com.android.contacts.RunMethodInstrumentation
41  */
42 public class RunMethodInstrumentation extends Instrumentation {
43 
44     private static final String TAG = "RunMethod";
45 
46     private static final String DEFAULT_CLASS = "AdbHelpers";
47 
48     private String className;
49     private String methodName;
50     private Bundle args;
51 
52     @Override
onCreate(Bundle arguments)53     public void onCreate(Bundle arguments) {
54         super.onCreate(arguments);
55 
56         InstrumentationRegistry.registerInstance(this, arguments);
57 
58         className = arguments.getString("class", getContext().getPackageName() + "." +
59                 DEFAULT_CLASS);
60         methodName = arguments.getString("method");
61         args = arguments;
62 
63         if (Log.isLoggable(TAG, Log.DEBUG)) {
64             Log.d(TAG, "Running " + className + "." + methodName);
65             Log.d(TAG, "args=" + args);
66         }
67 
68         if (arguments.containsKey("debug") && Boolean.parseBoolean(arguments.getString("debug"))) {
69             Debug.waitForDebugger();
70         }
71         start();
72     }
73 
74     @Override
onStart()75     public void onStart() {
76         if (Log.isLoggable(TAG, Log.DEBUG)) {
77             Log.d(TAG, "onStart");
78         }
79         super.onStart();
80 
81         if (className == null || methodName == null) {
82             Log.e(TAG, "Must supply class and method");
83             finish(Activity.RESULT_CANCELED, null);
84             return;
85         }
86 
87         // Wait for the Application to finish creating.
88         runOnMainSync(new Runnable() {
89             @Override
90             public void run() {
91                 if (Log.isLoggable(TAG, Log.DEBUG)) {
92                     Log.d(TAG, "acquired main thread from instrumentation");
93                 }
94             }
95         });
96 
97         try {
98             invokeMethod(args, className, methodName);
99         } catch (Exception e) {
100             e.printStackTrace();
101             finish(Activity.RESULT_CANCELED, null);
102             return;
103         }
104         // Maybe should let the method determine when this is called.
105         finish(Activity.RESULT_OK, null);
106     }
107 
invokeMethod(Bundle args, String className, String methodName)108     private void invokeMethod(Bundle args, String className, String methodName) throws
109             InvocationTargetException, IllegalAccessException, NoSuchMethodException,
110             ClassNotFoundException {
111         Context context;
112         Class<?> clazz = null;
113         try {
114             // Try to load from App's code
115             clazz = getTargetContext().getClassLoader().loadClass(className);
116             context = getTargetContext();
117         } catch (Exception e) {
118             // Try to load from Test App's code
119             clazz = getContext().getClassLoader().loadClass(className);
120             context = getContext();
121         }
122 
123         Object[] methodArgs = null;
124         Method method = null;
125 
126         try {
127             method = clazz.getMethod(methodName, Context.class, Bundle.class);
128             methodArgs = new Object[] { context, args };
129         } catch (NoSuchMethodException e) {
130         }
131 
132         if (method != null) {
133             method.invoke(clazz, methodArgs);
134             return;
135         }
136 
137         try {
138             method = clazz.getMethod(methodName, Context.class);
139             methodArgs = new Object[] { context };
140         } catch (NoSuchMethodException e) {
141         }
142 
143         if (method != null) {
144             method.invoke(clazz, methodArgs);
145             return;
146         }
147 
148         method = clazz.getMethod(methodName);
149         method.invoke(clazz);
150     }
151 }
152