1fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott/* 2fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott * Copyright (C) 2016 The Android Open Source Project 3fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott * 4fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott * Licensed under the Apache License, Version 2.0 (the "License"); 5fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott * you may not use this file except in compliance with the License. 6fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott * You may obtain a copy of the License at 7fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott * 8fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott * http://www.apache.org/licenses/LICENSE-2.0 9fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott * 10fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott * Unless required by applicable law or agreed to in writing, software 11fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott * distributed under the License is distributed on an "AS IS" BASIS, 12fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott * See the License for the specific language governing permissions and 14fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott * limitations under the License. 15fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott */ 16fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerottpackage com.android.contacts; 17fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott 18fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerottimport android.app.Activity; 19fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerottimport android.app.Instrumentation; 20fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerottimport android.content.Context; 21fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerottimport android.os.Bundle; 22aa5bdeb8bce9b273fa957b7cadbf447b99ea2d3bMarcus Hagerottimport android.os.Debug; 23fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerottimport android.support.test.InstrumentationRegistry; 24fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerottimport android.util.Log; 25fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott 26fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerottimport java.lang.reflect.InvocationTargetException; 27fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerottimport java.lang.reflect.Method; 28fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott 29fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott/** 30fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott * Runs a single static method specified via the arguments. 31fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott * 326927faf7e6e176246bca01d778bfbdff16635b6dMarcus Hagerott * Useful for manipulating the app state during manual testing. If the class argument is omitted 336927faf7e6e176246bca01d778bfbdff16635b6dMarcus Hagerott * this class will attempt to invoke a method in 346927faf7e6e176246bca01d778bfbdff16635b6dMarcus Hagerott * {@link com.android.contacts.tests.AdbHelpers} 35fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott * 36fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott * Valid signatures: void f(Context, Bundle), void f(Context), void f() 37fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott * 38fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott * Example usage: 39fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott * $ adb shell am instrument -e class com.android.contacts.Foo -e method bar -e someArg someValue\ 40fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott * -w com.google.android.contacts.tests/com.android.contacts.RunMethodInstrumentation 41fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott */ 42fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerottpublic class RunMethodInstrumentation extends Instrumentation { 43fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott 44fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott private static final String TAG = "RunMethod"; 45fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott 466927faf7e6e176246bca01d778bfbdff16635b6dMarcus Hagerott private static final String DEFAULT_CLASS = "AdbHelpers"; 476927faf7e6e176246bca01d778bfbdff16635b6dMarcus Hagerott 48fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott private String className; 49fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott private String methodName; 50fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott private Bundle args; 51fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott 52fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott @Override 53fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott public void onCreate(Bundle arguments) { 54fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott super.onCreate(arguments); 55fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott 56fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott InstrumentationRegistry.registerInstance(this, arguments); 57fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott 586927faf7e6e176246bca01d778bfbdff16635b6dMarcus Hagerott className = arguments.getString("class", getContext().getPackageName() + "." + 596927faf7e6e176246bca01d778bfbdff16635b6dMarcus Hagerott DEFAULT_CLASS); 60fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott methodName = arguments.getString("method"); 61fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott args = arguments; 62fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott 6357a0e98eed836b72dd3dc3540b9cac029266ed7cWenyi Wang if (Log.isLoggable(TAG, Log.DEBUG)) { 6457a0e98eed836b72dd3dc3540b9cac029266ed7cWenyi Wang Log.d(TAG, "Running " + className + "." + methodName); 6557a0e98eed836b72dd3dc3540b9cac029266ed7cWenyi Wang Log.d(TAG, "args=" + args); 6657a0e98eed836b72dd3dc3540b9cac029266ed7cWenyi Wang } 67fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott 68aa5bdeb8bce9b273fa957b7cadbf447b99ea2d3bMarcus Hagerott if (arguments.containsKey("debug") && Boolean.parseBoolean(arguments.getString("debug"))) { 69aa5bdeb8bce9b273fa957b7cadbf447b99ea2d3bMarcus Hagerott Debug.waitForDebugger(); 70aa5bdeb8bce9b273fa957b7cadbf447b99ea2d3bMarcus Hagerott } 71fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott start(); 72fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott } 73fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott 74073a091b4f94d7321b4e8f51e0ca240c5c264915Marcus Hagerott @Override 75fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott public void onStart() { 7657a0e98eed836b72dd3dc3540b9cac029266ed7cWenyi Wang if (Log.isLoggable(TAG, Log.DEBUG)) { 7757a0e98eed836b72dd3dc3540b9cac029266ed7cWenyi Wang Log.d(TAG, "onStart"); 7857a0e98eed836b72dd3dc3540b9cac029266ed7cWenyi Wang } 79fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott super.onStart(); 80fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott 81fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott if (className == null || methodName == null) { 82fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott Log.e(TAG, "Must supply class and method"); 83fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott finish(Activity.RESULT_CANCELED, null); 84fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott return; 85fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott } 86fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott 879c26abdc6458bb98c8354a2fb9ee9dda44ce2c45Marcus Hagerott // Wait for the Application to finish creating. 889c26abdc6458bb98c8354a2fb9ee9dda44ce2c45Marcus Hagerott runOnMainSync(new Runnable() { 899c26abdc6458bb98c8354a2fb9ee9dda44ce2c45Marcus Hagerott @Override 909c26abdc6458bb98c8354a2fb9ee9dda44ce2c45Marcus Hagerott public void run() { 9157a0e98eed836b72dd3dc3540b9cac029266ed7cWenyi Wang if (Log.isLoggable(TAG, Log.DEBUG)) { 9257a0e98eed836b72dd3dc3540b9cac029266ed7cWenyi Wang Log.d(TAG, "acquired main thread from instrumentation"); 9357a0e98eed836b72dd3dc3540b9cac029266ed7cWenyi Wang } 949c26abdc6458bb98c8354a2fb9ee9dda44ce2c45Marcus Hagerott } 959c26abdc6458bb98c8354a2fb9ee9dda44ce2c45Marcus Hagerott }); 969c26abdc6458bb98c8354a2fb9ee9dda44ce2c45Marcus Hagerott 97fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott try { 98fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott invokeMethod(args, className, methodName); 99fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott } catch (Exception e) { 100fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott e.printStackTrace(); 101fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott finish(Activity.RESULT_CANCELED, null); 102fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott return; 103fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott } 104fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott // Maybe should let the method determine when this is called. 105fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott finish(Activity.RESULT_OK, null); 106fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott } 107fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott 108fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott private void invokeMethod(Bundle args, String className, String methodName) throws 109fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott InvocationTargetException, IllegalAccessException, NoSuchMethodException, 110fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott ClassNotFoundException { 111fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott Context context; 112fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott Class<?> clazz = null; 113fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott try { 114fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott // Try to load from App's code 115fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott clazz = getTargetContext().getClassLoader().loadClass(className); 116fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott context = getTargetContext(); 117fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott } catch (Exception e) { 118fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott // Try to load from Test App's code 119fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott clazz = getContext().getClassLoader().loadClass(className); 120fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott context = getContext(); 121fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott } 122fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott 123fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott Object[] methodArgs = null; 124fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott Method method = null; 125fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott 126fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott try { 127fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott method = clazz.getMethod(methodName, Context.class, Bundle.class); 128fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott methodArgs = new Object[] { context, args }; 129fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott } catch (NoSuchMethodException e) { 130fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott } 131fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott 132fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott if (method != null) { 133fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott method.invoke(clazz, methodArgs); 134fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott return; 135fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott } 136fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott 137fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott try { 138fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott method = clazz.getMethod(methodName, Context.class); 139fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott methodArgs = new Object[] { context }; 140fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott } catch (NoSuchMethodException e) { 141fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott } 142fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott 143fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott if (method != null) { 144fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott method.invoke(clazz, methodArgs); 145fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott return; 146fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott } 147fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott 148fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott method = clazz.getMethod(methodName); 149fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott method.invoke(clazz); 150fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott } 151fd79e87e893054e20f86cbe5e0c48aa64ecd3955Marcus Hagerott} 152