package org.bbs.apklauncher; import java.lang.reflect.Field; import java.lang.reflect.Method; import org.bbs.apklauncher.ReflectUtil.ActivityReflectUtil; import android.R.array; import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.app.Activity; import android.app.Fragment; import android.app.Instrumentation; import android.content.Context; import android.content.Intent; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.util.Log; public class TargetInstrumentation extends InstrumentationWrapper { private static final String TAG = TargetInstrumentation.class.getSimpleName(); private CallBack mCallback; private Handler mUiHandler; public TargetInstrumentation(Instrumentation base, Handler uiHandler){ super(base); mUiHandler = uiHandler; } public void setCallBack(CallBack callback) { mCallback = callback; } public boolean processIntent(Intent intent) { if (null != mCallback) { return mCallback.onProcessIntent(intent); } return true; } @TargetApi(Build.VERSION_CODES.ECLAIR) public void disableActivityTransition(final Activity target) { Log.w(TAG, "disableActivityTransition now, need to be done in the future."); mUiHandler.post(new Runnable() { @Override public void run() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ECLAIR) { target.overridePendingTransition(0, 0); } } }); } public ActivityResult execStartActivity( Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode, Bundle options) { processIntent(intent); ActivityResult r = ReflectUtil.execStartActivity(getBase(), who, contextThread, token, target, intent, requestCode, options); disableActivityTransition(target); // FIXME activity transition // ((Activity)who).overridePendingTransition(0, 0); return r; } public void execStartActivities(Context who, IBinder contextThread, IBinder token, Activity target, Intent[] intents, Bundle options) { for (Intent intent: intents) { processIntent(intent); } ReflectUtil.execStartActivities(getBase(), who, contextThread, token, target, intents, options, ReflectUtil.myUseId()); disableActivityTransition(target); } public void execStartActivitiesAsUser(Context who, IBinder contextThread, IBinder token, Activity target, Intent[] intents, Bundle options, int userId) { for (Intent intent: intents) { processIntent(intent); } ReflectUtil.execStartActivitiesAsUser(getBase(), who, contextThread, token, target, intents, options, userId); disableActivityTransition(target); } @SuppressLint("NewApi") public ActivityResult execStartActivity( Context who, IBinder contextThread, IBinder token, Fragment target, Intent intent, int requestCode, Bundle options) { processIntent(intent); ActivityResult result = ReflectUtil.execStartActivity(getBase(), who, contextThread, token, target, intent, requestCode, options); disableActivityTransition(target.getActivity()); return result; } public static void injectInstrumentation(Object activity, CallBack callback) { Instrumentation intr = (Instrumentation) ActivityReflectUtil.getFiledValue(Activity.class, activity, "mInstrumentation"); Field f = ActivityReflectUtil.getFiled(Activity.class, activity, "mInstrumentation"); TargetInstrumentation wrapper = new TargetInstrumentation(intr, new Handler()); wrapper.setCallBack(callback); ActivityReflectUtil.setField(activity, f, wrapper); } public static interface CallBack { public boolean onProcessIntent(Intent intent); } static class ReflectUtil { public static ActivityResult execStartActivity(Object receiver, Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode, Bundle options) { try { // EmbeddedActivityAgent.ActivityReflectUtil.dumpMethod(Instrumentation.class, // "execStartActivity"); Method m = Instrumentation.class.getDeclaredMethod( "execStartActivity", new Class[] { Context.class, IBinder.class, IBinder.class, Activity.class, Intent.class, // int.class VS Integer.class int.class, Bundle.class }); m.setAccessible(true); return (ActivityResult) m.invoke(receiver, new Object[] { who, contextThread, token, target, intent, requestCode, options }); } catch (Exception e) { ActivityReflectUtil.dumpMethod(Instrumentation.class, "execStartActivity"); throw new RuntimeException("error in execStartActivity.", e); } } public static void execStartActivitiesAsUser(Instrumentation receiver, Context who, IBinder contextThread, IBinder token, Activity target, Intent[] intents, Bundle options, int userId) { try { // EmbeddedActivityAgent.ActivityReflectUtil.dumpMethod(Instrumentation.class, // "execStartActivitiesAsUser"); Method m = Instrumentation.class.getDeclaredMethod( "execStartActivitiesAsUser", new Class[] { Context.class, IBinder.class, IBinder.class, Activity.class, Intent.class, Bundle.class, // int.class VS Integer.class int.class }); m.setAccessible(true); m.invoke(receiver, new Object[] { who, contextThread, token, target, intents, options, userId }); } catch (Exception e) { ActivityReflectUtil.dumpMethod(Instrumentation.class, "execStartActivitiesAsUser"); throw new RuntimeException( "error in execStartActivitiesAsUser.", e); } } @SuppressLint("NewApi") public static ActivityResult execStartActivity( Instrumentation receiver, Context who, IBinder contextThread, IBinder token, Fragment target, Intent intent, int requestCode, Bundle options) { try { // EmbeddedActivityAgent.ActivityReflectUtil.dumpMethod(Instrumentation.class, // "execStartActivity"); Method m = Instrumentation.class.getDeclaredMethod( "execStartActivity", new Class[] { Context.class, IBinder.class, IBinder.class, Fragment.class, // int.class VS Integer.class int.class, Bundle.class }); m.setAccessible(true); return (ActivityResult) m.invoke(receiver, new Object[] { who, contextThread, token, target, intent, requestCode, options }); } catch (Exception e) { ActivityReflectUtil.dumpMethod(Instrumentation.class, "execStartActivity"); throw new RuntimeException("error in execStartActivity.", e); } } public static Object execStartActivities(Instrumentation receiver, Context who, IBinder contextThread, IBinder token, Activity target, Intent[] intents, Bundle options, int myUseId) { try { // EmbeddedActivityAgent.ActivityReflectUtil.dumpMethod(Instrumentation.class, // "execStartActivities"); Method m = Instrumentation.class.getDeclaredMethod( "execStartActivities", new Class[] { Context.class, IBinder.class, IBinder.class, Activity.class, array.class, Bundle.class, // int.class VS Integer.class int.class }); m.setAccessible(true); return (ActivityResult) m.invoke(receiver, new Object[] { who, contextThread, token, target, intents, options, myUseId }); } catch (Exception e) { ActivityReflectUtil.dumpMethod(Instrumentation.class, "execStartActivities"); throw new RuntimeException("error in execStartActivities.", e); } } public static int myUseId() { int userId = -1; try { Method myUserIdM = Class.forName("android.os.UserHandle") .getDeclaredMethod("myUseId", (Class[]) null); myUserIdM.setAccessible(true); userId = ((Integer) myUserIdM.invoke(null, (Object[]) null)); } catch (Exception e) { e.printStackTrace(); } return userId; } } }