/**
* OpenAtlasForAndroid Project
* The MIT License (MIT) Copyright (OpenAtlasForAndroid) 2015 Bunny Blue,achellies
* <p>
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
* and associated documentation files (the "Software"), to deal in the Software
* without restriction, including without limitation the rights to use, copy, modify,
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to the following conditions:
* <p>
* The above copyright notice and this permission notice shall be included in all copies
* or substantial portions of the Software.
* <p>
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
* FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* @author BunnyBlue
**/
package com.openatlas.runtime;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.Application;
import android.app.Fragment;
import android.app.Instrumentation;
import android.app.UiAutomation;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.ResolveInfo;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.text.TextUtils;
import android.view.KeyEvent;
import android.view.MotionEvent;
import com.openatlas.framework.OpenAtlasInternalConstant;
import com.openatlas.bundleInfo.BundleInfoList;
import com.openatlas.framework.BundleClassLoader;
import com.openatlas.framework.BundleImpl;
import com.openatlas.framework.Framework;
import com.openatlas.hack.Hack;
import com.openatlas.hack.Hack.HackDeclaration.HackAssertionException;
import com.openatlas.hack.Hack.HackedClass;
import com.openatlas.hack.Hack.HackedMethod;
import com.openatlas.hack.OpenAtlasHacks;
import com.openatlas.log.Logger;
import com.openatlas.log.LoggerFactory;
import com.openatlas.log.OpenAtlasMonitor;
import com.openatlas.util.StringUtils;
import org.osgi.framework.BundleException;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
/**Hack Instrumentation,replace Instrumentation with InstrumentationHook
* ****/
public class InstrumentationHook extends Instrumentation {
static final Logger log;
private Context context;
private Instrumentation mBase;
private HackedClass<Object> mInstrumentationInvoke;
private HackedMethod mExecStartActivity;
private HackedMethod mExecStartActivityFragment;
private interface ExecStartActivityCallback {
ActivityResult execStartActivity();
}
class ExecStartActivityCallbackImpl implements ExecStartActivityCallback {
final IBinder contextThread;
final Intent intent;
final int requestCode;
final Activity target;
final IBinder token;
final Context who;
ExecStartActivityCallbackImpl(Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode) {
this.who = context;
this.contextThread = contextThread;
this.token = token;
this.target = target;
this.intent = intent;
this.requestCode = requestCode;
}
@Override
public ActivityResult execStartActivity() {
if (mExecStartActivity == null) {
throw new NullPointerException("could not hook Instrumentation!");
}
try {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
return (ActivityResult) mExecStartActivity.invoke(mBase, this.who, this.contextThread, this.token,
this.target, this.intent, this.requestCode, null);
} else {
return (ActivityResult) mExecStartActivity.invoke(mBase, this.who, this.contextThread, this.token,
this.target, this.intent, this.requestCode);
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
}
class ExecStartActivityCallbackImpl_JELLY_BEAN implements ExecStartActivityCallback {
final IBinder contextThread;
final Intent intent;
final Bundle options;
final int requestCode;
final Activity target;
final IBinder token;
final Context who;
ExecStartActivityCallbackImpl_JELLY_BEAN(Context context, IBinder contextThread, IBinder token, Activity activity, Intent intent,
int requestCode, Bundle options) {
this.who = context;
this.contextThread = contextThread;
this.token = token;
this.target = activity;
this.intent = intent;
this.requestCode = requestCode;
this.options = options;
}
@Override
public ActivityResult execStartActivity() {
if (mExecStartActivity == null) {
throw new NullPointerException("could not hook Instrumentation!");
}
try {
return (ActivityResult) mExecStartActivity.invoke(mBase, this.who, this.contextThread, this.token,
this.target, this.intent, this.requestCode, this.options);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
}
class ExecStartFrgmentImpl_ICE_CREAM_SANDWICH implements ExecStartActivityCallback {
final IBinder contextThread;
final Intent intent;
final int requestCode;
final Fragment target;
final IBinder token;
final Context who;
ExecStartFrgmentImpl_ICE_CREAM_SANDWICH(Context context, IBinder contextThread, IBinder token, Fragment fragment, Intent intent, int requestCode) {
this.who = context;
this.contextThread = contextThread;
this.token = token;
this.target = fragment;
this.intent = intent;
this.requestCode = requestCode;
}
@Override
public ActivityResult execStartActivity() {
if (mExecStartActivityFragment == null) {
throw new NullPointerException("could not hook Instrumentation!");
}
try {
return (ActivityResult) mExecStartActivityFragment.invoke(mBase, this.who, this.contextThread, this.token,
this.target, this.intent, this.requestCode);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
}
class ExecStartFrgmentImpl_JELLY_BEAN implements ExecStartActivityCallback {
final IBinder contextThread;
final Intent intent;
final Bundle options;
final int requestCode;
final Fragment target;
final IBinder token;
final Context who;
ExecStartFrgmentImpl_JELLY_BEAN(Context context, IBinder contextThread, IBinder token, Fragment fragment, Intent intent,
int requestCode, Bundle options) {
this.who = context;
this.contextThread = contextThread;
this.token = token;
this.target = fragment;
this.intent = intent;
this.requestCode = requestCode;
this.options = options;
}
@Override
public ActivityResult execStartActivity() {
if (mExecStartActivityFragment == null) {
throw new NullPointerException("could not hook Instrumentation!");
}
try {
return (ActivityResult) mExecStartActivityFragment.invoke(mBase, this.who, this.contextThread, this.token,
this.target, this.intent, this.requestCode, this.options);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
}
static {
log = LoggerFactory.getInstance("InstrumentationHook");
}
/****
*
* public ActivityResult execStartActivity( Context who, IBinder
* contextThread, IBinder token, Activity target, Intent intent, int
* requestCode);
* ***/
public InstrumentationHook(Instrumentation instrumentation, Context context) {
this.context = context;
this.mBase = instrumentation;
try {
mInstrumentationInvoke = Hack.into("android.app.Instrumentation");
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
mExecStartActivity = mInstrumentationInvoke.method("execStartActivity", Context.class,
IBinder.class, IBinder.class, Activity.class, Intent.class, int.class, Bundle.class);
} else {
mExecStartActivity = mInstrumentationInvoke.method("execStartActivity", Context.class,
IBinder.class, IBinder.class, Activity.class, Intent.class, int.class);
}
if (Build.VERSION.SDK_INT>Build.VERSION_CODES.LOLLIPOP_MR1){
log.debug("current sdk > LOLLIPOP,skip hack");
}else if (Build.VERSION.SDK_INT > Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
mExecStartActivityFragment = mInstrumentationInvoke.method("execStartActivity", Context.class,
IBinder.class, IBinder.class, Fragment.class, Intent.class, int.class, Bundle.class);
} else {
mExecStartActivityFragment = mInstrumentationInvoke.method("execStartActivity", Context.class,
IBinder.class, IBinder.class, Fragment.class, Intent.class, int.class);
}
} catch (HackAssertionException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
}
private void HandleResourceNotFound(Activity activity, Bundle bundle, Exception exception) {
if (OpenAtlasHacks.ContextThemeWrapper_mResources != null) {
String detailMessage;
try {
List<?> assetPathFromResources = getAssetPathFromResources(OpenAtlasHacks.ContextThemeWrapper_mResources
.get(activity));
detailMessage = "(1)Paths in ContextThemeWrapper_mResources:" + assetPathFromResources + " paths in runtime:"
+ DelegateResources.getAssetHistoryPaths();
} catch (Exception e) {
detailMessage = "(2)paths in runtime:" + DelegateResources.getAssetHistoryPaths() + " getAssetPath fail: " + e;
}
throw new RuntimeException(detailMessage, exception);
}
throw new RuntimeException("(3)ContextThemeWrapper_mResources is null paths in runtime:"
+ DelegateResources.getAssetHistoryPaths(), exception);
}
public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode) {
return execStartActivityInternal(this.context, intent, new ExecStartActivityCallbackImpl(who, contextThread, token, target,
intent, requestCode));
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle bundle) {
return execStartActivityInternal(this.context, intent, new ExecStartActivityCallbackImpl_JELLY_BEAN(who, contextThread, token, target,
intent, requestCode, bundle));
}
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Fragment fragment,
Intent intent, int requestCode) {
return execStartActivityInternal(this.context, intent, new ExecStartFrgmentImpl_ICE_CREAM_SANDWICH(who, contextThread, token,
fragment, intent, requestCode));
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Fragment fragment,
Intent intent, int requestCode, Bundle bundle) {
return execStartActivityInternal(this.context, intent, new ExecStartFrgmentImpl_JELLY_BEAN(who, contextThread, token,
fragment, intent, requestCode, bundle));
}
private ActivityResult execStartActivityInternal(Context context, Intent intent, ExecStartActivityCallback execStartActivityCallback) {
String packageName = null;
String mComponentName = null;
ActivityResult activityResult = null;
if (intent.getComponent() != null) {
packageName = intent.getComponent().getPackageName();
mComponentName = intent.getComponent().getClassName();
} else {
ResolveInfo resolveActivity = context.getPackageManager().resolveActivity(intent, 0);
if (resolveActivity == null || resolveActivity.activityInfo == null) {
} else {
packageName = resolveActivity.activityInfo.packageName;
mComponentName = resolveActivity.activityInfo.name;
}
}
if (mComponentName == null) {
try {
return execStartActivityCallback.execStartActivity();
} catch (Exception e) {
log.error("Failed to start Activity for " + packageName + " " + mComponentName + e);
return activityResult;
}
}
try {
ClassLoadFromBundle.checkInstallBundleIfNeed(mComponentName);
if (!StringUtils.equals(context.getPackageName(), packageName)) {
return execStartActivityCallback.execStartActivity();
}
if (DelegateComponent.locateComponent(mComponentName) != null) {
return execStartActivityCallback.execStartActivity();
}
try {
if (Framework.getSystemClassLoader().loadClass(mComponentName) != null) {
return execStartActivityCallback.execStartActivity();
}
return activityResult;
} catch (ClassNotFoundException e) {
OpenAtlasMonitor.getInstance().trace(OpenAtlasMonitor.BUNDLE_INSTALL_FAIL, mComponentName, "",
"Failed to load bundle even in system classloader", e);
log.error("Can't find class " + mComponentName);
fallBackToClassNotFoundCallback(context, intent, mComponentName);
return activityResult;
}
} catch (Exception e3) {
log.error("Failed to load bundle for " + mComponentName + e3);
fallBackToClassNotFoundCallback(context, intent, mComponentName);
return activityResult;
}
}
private void fallBackToClassNotFoundCallback(Context context, Intent intent, String className) {
if (Framework.getClassNotFoundCallback() != null) {
if (intent.getComponent() == null && !TextUtils.isEmpty(className)) {
intent.setClassName(context, className);
}
if (intent.getComponent() != null) {
Framework.getClassNotFoundCallback().returnIntent(intent);
}
}
}
/**
* Perform instantiation of an {@link Activity} object. This method is intended for use with
* unit tests, such as android.test.ActivityUnitTestCase. The activity will be useable
* locally but will be missing some of the linkages necessary for use within the sytem.
*
* @param clazz The Class of the desired Activity
* @param context The base context for the activity to use
* @param token The token for this activity to communicate with
* @param application The application object (if any)
* @param intent The intent that started this Activity
* @param activityInfo ActivityInfo from the manifest
* @param title The title, typically retrieved from the ActivityInfo record
* @param parent The parent Activity (if any)
* @param id The embedded Id (if any)
* @param lastNonConfigurationInstance Arbitrary object that will be
* available via {@link Activity#getLastNonConfigurationInstance()
* Activity.getLastNonConfigurationInstance()}.
* @return Returns the instantiated activity
* @throws InstantiationException
* @throws IllegalAccessException
*/
@Override
public Activity newActivity(Class<?> clazz, Context context, IBinder token, Application application,
Intent intent, ActivityInfo activityInfo, CharSequence title, Activity parent, String id,
Object lastNonConfigurationInstance) throws InstantiationException, IllegalAccessException {
Activity newActivity = this.mBase.newActivity(clazz, context, token, application, intent, activityInfo,
title, parent, id, lastNonConfigurationInstance);
if (RuntimeVariables.androidApplication.getPackageName().equals(activityInfo.packageName)
&& OpenAtlasHacks.ContextThemeWrapper_mResources != null) {
OpenAtlasHacks.ContextThemeWrapper_mResources.set(newActivity, RuntimeVariables.delegateResources);
}
return newActivity;
}
/**
* Perform instantiation of the process's {@link Activity} object. The
* default implementation provides the normal system behavior.
*
* @param cl The ClassLoader with which to instantiate the object.
* @param className The name of the class implementing the Activity
* object.
* @param intent The Intent object that specified the activity class being
* instantiated.
*
* @return The newly instantiated Activity object.
*/
@Override
public Activity newActivity(ClassLoader cl, String className, Intent intent) throws InstantiationException,
IllegalAccessException, ClassNotFoundException {
Activity newActivity;
String defaultBootActivityName = null;
try {
newActivity = this.mBase.newActivity(cl, className, intent);
} catch (ClassNotFoundException e) {
ClassNotFoundException classNotFoundException = e;
CharSequence property = Framework.getProperty(OpenAtlasInternalConstant.BOOT_ACTIVITY,
OpenAtlasInternalConstant.BOOT_ACTIVITY_DEFAULT);
if (TextUtils.isEmpty(property)) {
defaultBootActivityName = OpenAtlasInternalConstant.BOOT_ACTIVITY_DEFAULT;
} else {
@SuppressWarnings("unused")
CharSequence charSequence = property;
}
if (TextUtils.isEmpty(defaultBootActivityName)) {
throw classNotFoundException;
}
@SuppressWarnings("deprecation")
List<RunningTaskInfo> runningTasks = ((ActivityManager) this.context.getSystemService(Context.ACTIVITY_SERVICE))
.getRunningTasks(1);
if (runningTasks != null && runningTasks.size() > 0
&& runningTasks.get(0).numActivities > 1
&& Framework.getClassNotFoundCallback() != null) {
if (intent.getComponent() == null) {
intent.setClassName(this.context, className);
}
Framework.getClassNotFoundCallback().returnIntent(intent);
}
log.warn("Could not find activity class: " + className);
log.warn("Redirect to welcome activity: " + defaultBootActivityName);
newActivity = this.mBase.newActivity(cl, defaultBootActivityName, intent);
}
if ((cl instanceof DelegateClassLoader) && OpenAtlasHacks.ContextThemeWrapper_mResources != null) {
OpenAtlasHacks.ContextThemeWrapper_mResources.set(newActivity, RuntimeVariables.delegateResources);
}
return newActivity;
}
private List<String> getAssetPathFromResources(Resources resources) {
try {
return DelegateResources
.getOriginAssetsPath((AssetManager) OpenAtlasHacks.Resources_mAssets.get(resources));
} catch (Exception e) {
log.debug("DelegateResource" + e.getCause());
return null;
}
}
/**
* Perform calling of an activity's {@link Activity#onCreate}
* method. The default implementation simply calls through to that method.
*
* @param activity The activity being created.
* @param icicle The previously frozen state (or null) to pass through to
* onCreate().
*/
@Override
public void callActivityOnCreate(Activity activity, Bundle icicle) {
if (RuntimeVariables.androidApplication.getPackageName().equals(activity.getPackageName())) {
ContextImplHook contextImplHook = new ContextImplHook(activity.getBaseContext(), activity.getClass()
.getClassLoader());
if (!(OpenAtlasHacks.ContextThemeWrapper_mBase == null || OpenAtlasHacks.ContextThemeWrapper_mBase.getField() == null)) {
OpenAtlasHacks.ContextThemeWrapper_mBase.set(activity, contextImplHook);
}
OpenAtlasHacks.ContextWrapper_mBase.set(activity, contextImplHook);
if (activity.getClass().getClassLoader() instanceof BundleClassLoader) {
try {
((BundleClassLoader) activity.getClass().getClassLoader()).getBundle().startBundle();
} catch (BundleException e) {
log.error(e.getMessage() + " Caused by: ", e.getNestedException());
}
}
String property = Framework.getProperty(OpenAtlasInternalConstant.BOOT_ACTIVITY, OpenAtlasInternalConstant.BOOT_ACTIVITY);
if (TextUtils.isEmpty(property)) {
property = OpenAtlasInternalConstant.BOOT_ACTIVITY;
}
try {
ensureResourcesInjected(activity);
this.mBase.callActivityOnCreate(activity, icicle);
return;
} catch (Exception e2) {
if (!e2.toString().contains("android.content.res.Resources")
|| e2.toString().contains("OutOfMemoryError")) {
e2.printStackTrace();
}
HandleResourceNotFound(activity, icicle, e2);
return;
}
}
this.mBase.callActivityOnCreate(activity, icicle);
}
@Override
@TargetApi(18)
public UiAutomation getUiAutomation() {
return this.mBase.getUiAutomation();
}
@Override
public void onCreate(Bundle bundle) {
this.mBase.onCreate(bundle);
}
@Override
public void start() {
this.mBase.start();
}
@Override
public void onStart() {
this.mBase.onStart();
}
@Override
public boolean onException(Object obj, Throwable th) {
return this.mBase.onException(obj, th);
}
@Override
public void sendStatus(int i, Bundle bundle) {
this.mBase.sendStatus(i, bundle);
}
@Override
public void finish(int i, Bundle bundle) {
this.mBase.finish(i, bundle);
}
@Override
public void setAutomaticPerformanceSnapshots() {
this.mBase.setAutomaticPerformanceSnapshots();
}
@Override
public void startPerformanceSnapshot() {
this.mBase.startPerformanceSnapshot();
}
@Override
public void endPerformanceSnapshot() {
this.mBase.endPerformanceSnapshot();
}
private void ensureResourcesInjected(Activity activity) {
ContextImplHook contextImplHook = new ContextImplHook(activity.getBaseContext(), activity.getClass()
.getClassLoader());
if (OpenAtlasHacks.ContextThemeWrapper_mResources != null) {
try {
validateActivityResource(activity);
} catch (Throwable th) {
}
OpenAtlasHacks.ContextThemeWrapper_mResources.set(activity, RuntimeVariables.delegateResources);
}
if (!(OpenAtlasHacks.ContextThemeWrapper_mBase == null || OpenAtlasHacks.ContextThemeWrapper_mBase.getField() == null)) {
OpenAtlasHacks.ContextThemeWrapper_mBase.set(activity, contextImplHook);
}
OpenAtlasHacks.ContextWrapper_mBase.set(activity, contextImplHook);
}
private boolean validateActivityResource(Activity activity) {
String absolutePath;
Resources resources;
String logInfo = null;
BundleImpl bundleImpl = (BundleImpl) Framework.getBundle(BundleInfoList.getInstance().getBundleNameForComponet(
activity.getLocalClassName()));
if (bundleImpl != null) {
absolutePath = bundleImpl.getArchive().getArchiveFile().getAbsolutePath();
} else {
absolutePath = null;
}
if (OpenAtlasHacks.ContextThemeWrapper_mResources != null) {
resources = OpenAtlasHacks.ContextThemeWrapper_mResources.get(activity);
} else {
resources = activity.getResources();
}
Resources delegateResource = RuntimeVariables.delegateResources;
if (resources == delegateResource) {
return true;
}
List<?> assetPathFromResources = getAssetPathFromResources(resources);
String assetHistoryPaths = DelegateResources.getAssetHistoryPaths();
List<?> assetPathFromDelegateResources = getAssetPathFromResources(delegateResource);
if (!(absolutePath == null || assetPathFromResources == null || assetPathFromResources.contains(absolutePath))) {
logInfo = "Activity Resources path not contains:"
+ bundleImpl.getArchive().getArchiveFile().getAbsolutePath();
if (!assetHistoryPaths.contains(absolutePath)) {
logInfo = logInfo + "paths in history not contains:"
+ bundleImpl.getArchive().getArchiveFile().getAbsolutePath();
}
if (!assetPathFromDelegateResources.contains(absolutePath)) {
logInfo = logInfo + "paths in runtime not contains:"
+ bundleImpl.getArchive().getArchiveFile().getAbsolutePath();
}
if (!bundleImpl.getArchive().getArchiveFile().exists()) {
logInfo = logInfo + " Bundle archive file not exist:"
+ bundleImpl.getArchive().getArchiveFile().getAbsolutePath();
}
logInfo = logInfo + " Activity Resources paths length:" + assetPathFromResources.size();
}
if (logInfo == null) {
return true;
}
OpenAtlasMonitor.getInstance().trace(Integer.valueOf(-4), "", "", logInfo);
return false;
}
@Override
public void onDestroy() {
this.mBase.onDestroy();
}
@Override
public Context getContext() {
return this.mBase.getContext();
}
@Override
public ComponentName getComponentName() {
return this.mBase.getComponentName();
}
@Override
public Context getTargetContext() {
return this.mBase.getTargetContext();
}
@Override
public boolean isProfiling() {
return this.mBase.isProfiling();
}
@Override
public void startProfiling() {
this.mBase.startProfiling();
}
@Override
public void stopProfiling() {
this.mBase.stopProfiling();
}
/**
* Force the global system in or out of touch mode. This can be used if
* your instrumentation relies on the UI being in one more or the other
* when it starts.
*
* @param inTouch Set to true to be in touch mode, false to be in
* focus mode.
*/
@Override
public void setInTouchMode(boolean inTouch) {
this.mBase.setInTouchMode(inTouch);
}
@Override
public void waitForIdle(Runnable runnable) {
this.mBase.waitForIdle(runnable);
}
@Override
public void waitForIdleSync() {
this.mBase.waitForIdleSync();
}
@Override
public void runOnMainSync(Runnable runnable) {
this.mBase.runOnMainSync(runnable);
}
@Override
public Activity startActivitySync(Intent intent) {
return this.mBase.startActivitySync(intent);
}
@Override
public void addMonitor(ActivityMonitor monitor) {
this.mBase.addMonitor(monitor);
}
/**
* A convenience wrapper for {@link #addMonitor(ActivityMonitor)} that
* creates an intent filter matching {@link ActivityMonitor} for you and
* returns it.
*
* @param filter The set of intents this monitor is responsible for.
* @param result A canned result to return if the monitor is hit; can
* be null.
* @param block Controls whether the monitor should block the activity
* start (returning its canned result) or let the call
* proceed.
*
* @return The newly created and added activity monitor.
*
* @see #addMonitor(ActivityMonitor)
* @see #checkMonitorHit
*/
@Override
public ActivityMonitor addMonitor(IntentFilter filter, ActivityResult result, boolean block) {
return this.mBase.addMonitor(filter, result, block);
}
/**
* A convenience wrapper for {@link #addMonitor(ActivityMonitor)} that
* creates a class matching {@link ActivityMonitor} for you and returns it.
*
* @param cls The activity class this monitor is responsible for.
* @param result A canned result to return if the monitor is hit; can
* be null.
* @param block Controls whether the monitor should block the activity
* start (returning its canned result) or let the call
* proceed.
*
* @return The newly created and added activity monitor.
*
* @see #addMonitor(ActivityMonitor)
* @see #checkMonitorHit
*/
@Override
public ActivityMonitor addMonitor(String cls, ActivityResult result, boolean block) {
return this.mBase.addMonitor(cls, result, block);
}
/**
* Test whether an existing {@link ActivityMonitor} has been hit. If the
* monitor has been hit at least <var>minHits</var> times, then it will be
* removed from the activity monitor list and true returned. Otherwise it
* is left as-is and false is returned.
*
* @param monitor The ActivityMonitor to check.
* @param minHits The minimum number of hits required.
*
* @return True if the hit count has been reached, else false.
*
* @see #addMonitor
*/
@Override
public boolean checkMonitorHit(ActivityMonitor monitor, int minHits) {
return this.mBase.checkMonitorHit(monitor, minHits);
}
@Override
public Activity waitForMonitor(ActivityMonitor monitor) {
return this.mBase.waitForMonitor(monitor);
}
/**
* Wait for an existing {@link ActivityMonitor} to be hit till the timeout
* expires. Once the monitor has been hit, it is removed from the activity
* monitor list and the first created Activity object that matched it is
* returned. If the timeout expires, a null object is returned.
*
* @param monitor The ActivityMonitor to wait for.
* @param timeOut The timeout value in secs.
*
* @return The Activity object that matched the monitor.
*/
@Override
public Activity waitForMonitorWithTimeout(ActivityMonitor monitor, long timeOut) {
return this.mBase.waitForMonitorWithTimeout(monitor, timeOut);
}
@Override
public void removeMonitor(ActivityMonitor monitor) {
this.mBase.removeMonitor(monitor);
}
/**
* Execute a particular menu item.
*
* @param targetActivity The activity in question.
* @param id The identifier associated with the menu item.
* @param flag Additional flags, if any.
* @return Whether the invocation was successful (for example, it could be
* false if item is disabled).
*/
@Override
public boolean invokeMenuActionSync(Activity targetActivity, int id, int flag) {
return this.mBase.invokeMenuActionSync(targetActivity, id, flag);
}
/**
* Show the context menu for the currently focused view and executes a
* particular context menu item.
*
* @param targetActivity The activity in question.
* @param id The identifier associated with the context menu item.
* @param flag Additional flags, if any.
* @return Whether the invocation was successful (for example, it could be
* false if item is disabled).
*/
@Override
public boolean invokeContextMenuAction(Activity targetActivity, int id, int flag) {
return this.mBase.invokeContextMenuAction(targetActivity, id, flag);
}
/**
* Sends the key events corresponding to the text to the app being
* instrumented.
*
* @param text The text to be sent.
*/
@Override
public void sendStringSync(String text) {
this.mBase.sendStringSync(text);
}
@Override
public void sendKeySync(KeyEvent keyEvent) {
this.mBase.sendKeySync(keyEvent);
}
/**
* Sends an up and down key event sync to the currently focused window.
*
* @param key The integer keycode for the event.
*/
@Override
public void sendKeyDownUpSync(int key) {
this.mBase.sendKeyDownUpSync(key);
}
/**
* Higher-level method for sending both the down and up key events for a
* particular character key code. Equivalent to creating both KeyEvent
* objects by hand and calling {@link #sendKeySync}. The event appears
* as if it came from keyboard 0, the built in one.
*
* @param keyCode The key code of the character to send.
*/
@Override
public void sendCharacterSync(int keyCode) {
this.mBase.sendCharacterSync(keyCode);
}
@Override
public void sendPointerSync(MotionEvent motionEvent) {
this.mBase.sendPointerSync(motionEvent);
}
@Override
public void sendTrackballEventSync(MotionEvent motionEvent) {
this.mBase.sendTrackballEventSync(motionEvent);
}
/**
* Perform instantiation of the process's {@link Application} object. The
* default implementation provides the normal system behavior.
*
* @param classLoader The ClassLoader with which to instantiate the object.
* @param className The name of the class implementing the Application
* object.
* @param context The context to initialize the application with
*
* @return The newly instantiated Application object.
*/
@Override
public Application newApplication(ClassLoader classLoader, String className, Context context)
throws InstantiationException, IllegalAccessException, ClassNotFoundException {
return this.mBase.newApplication(classLoader, className, context);
}
@Override
public void callApplicationOnCreate(Application application) {
this.mBase.callApplicationOnCreate(application);
}
@Override
public void callActivityOnDestroy(Activity activity) {
this.mBase.callActivityOnDestroy(activity);
}
@Override
public void callActivityOnRestoreInstanceState(Activity activity, Bundle bundle) {
this.mBase.callActivityOnRestoreInstanceState(activity, bundle);
}
@Override
public void callActivityOnPostCreate(Activity activity, Bundle bundle) {
this.mBase.callActivityOnPostCreate(activity, bundle);
}
@Override
public void callActivityOnNewIntent(Activity activity, Intent intent) {
this.mBase.callActivityOnNewIntent(activity, intent);
}
@Override
public void callActivityOnStart(Activity activity) {
this.mBase.callActivityOnStart(activity);
}
@Override
public void callActivityOnRestart(Activity activity) {
this.mBase.callActivityOnRestart(activity);
}
@Override
public void callActivityOnResume(Activity activity) {
this.mBase.callActivityOnResume(activity);
}
@Override
public void callActivityOnStop(Activity activity) {
this.mBase.callActivityOnStop(activity);
}
@Override
public void callActivityOnSaveInstanceState(Activity activity, Bundle bundle) {
this.mBase.callActivityOnSaveInstanceState(activity, bundle);
}
@Override
public void callActivityOnPause(Activity activity) {
this.mBase.callActivityOnPause(activity);
}
@Override
public void callActivityOnUserLeaving(Activity activity) {
this.mBase.callActivityOnUserLeaving(activity);
}
@Override
public void startAllocCounting() {
this.mBase.startAllocCounting();
}
@Override
public void stopAllocCounting() {
this.mBase.stopAllocCounting();
}
@Override
public Bundle getAllocCounts() {
return this.mBase.getAllocCounts();
}
@Override
public Bundle getBinderCounts() {
return this.mBase.getBinderCounts();
}
}