package org.bbs.osgi.activity; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import android.annotation.SuppressLint; import android.app.Activity; import android.app.Application; import android.app.Dialog; import android.content.Context; import android.content.ContextWrapper; import android.content.Intent; import android.content.res.Configuration; import android.content.res.Resources; import android.os.Bundle; import android.os.PersistableBundle; import android.util.Log; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.ContextThemeWrapper; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.Window; public class ReflectUtil { private static final String TAG = ReflectUtil.class.getSimpleName(); public static void dumpMethod(Class clazz, String methodName){ Method[] methods = clazz.getDeclaredMethods(); for (Method m: methods) { if (m.getName().startsWith(methodName)) { Log.d(TAG, "method: " + m); // Log.d(TAG, "method name: " + m.getName()); // Log.d(TAG, "paramter: ["); // Class<?>[] parameterTypes = m.getParameterTypes(); // for (Class p : parameterTypes) { // Log.d(TAG, "" + p.getCanonicalName()); // } // Log.d(TAG, "]"); } } } public static void dumpField(Class clazz, String fieldName){ Field[] fs = clazz.getDeclaredFields(); for (Field f: fs) { if (f.getName().startsWith(fieldName)) { Log.d(TAG, "method name: " + f.getName()); Log.d(TAG, "]"); } } } public static void copyFields(Class clazz, String[] fields, Object host, Activity target) { for (String f : fields) { Field declaredField = null; try { declaredField = clazz.getDeclaredField(f); setField(target, declaredField, getFiledValue(clazz, host, f)); } catch (Exception e) { throw new RuntimeException("setField(). field: " + declaredField, e); } } } public static void setField(Object object, Field field, Object value) { field.setAccessible(true); try { field.set(object, value); } catch (Exception e) { throw new RuntimeException("setField(). field: " + field, e); } } public static Field getFiled(Class clazz, Object object, String fieldName) { try { Field declaredField = clazz.getDeclaredField(fieldName); return declaredField; } catch (Exception e) { throw new RuntimeException("getFiled(). fieldName: " + fieldName, e); } } public static Object getFiledValue(Class clazz, Object object, String fieldName) { Object f = null; try { Field declaredField = getFiled(clazz, object, fieldName); declaredField.setAccessible(true); f = declaredField.get(object); return f; } catch (Exception e) { throw new RuntimeException("getFiledValue(). class: " + clazz + " object: " + object + " field: " + fieldName, e); } } public static class ApplicationUtil { public static void callAttach(Application app, Context baseContext){ try { Method m = Class.forName("android.app.Application").getDeclaredMethod("attach", new Class[]{Context.class}); m.setAccessible(true); m.invoke(app, new Object[]{baseContext}); } catch (NoSuchMethodException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static void copyFields(Application host, Application target) { String[] fields = new String[] { "mMainThread", "mInstrumentation", "mToken", "mIdent", "mApplication", "mIntent", "mActivityInfo", "mTitle", "mParent", "mEmbeddedID", "mLastNonConfigurationInstances", "mFragments",// java.lang.IllegalStateException // FragmentManagerImpl.moveToState "mWindow", "mWindowManager", "mCurrentConfig" }; copyFields(Application.class, fields, host, target); } public static void copyFields(Class clazz, String[] fields, Application host, Application target) { try { for (String f : fields) { Field declaredField = clazz.getDeclaredField(f); setField(target, declaredField, getFiledValue(Class.forName("android.app.Application"), host, f)); } } catch (NoSuchFieldException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } /** * keep function name consistency with {@link Activity} * * @author bysong * */ public static class ActivityReflectUtil extends ReflectUtil { public static void onClick(Activity activity, View view){ try { Method m = Activity.class.getDeclaredMethod("onClick", new Class[]{View.class}); m.setAccessible(true); m.invoke(activity, new Object[]{view}); } catch (Exception e) { throw new RuntimeException("error in onCreate", e); } } public static void copyBaseContext(Activity target, Context base) { try { Field f = ContextWrapper.class.getDeclaredField("mBase"); f.setAccessible(true); f.set(target, base); } catch (NoSuchFieldException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static void copyNewResouce(Activity target, Resources source) { try { Field f = ContextThemeWrapper.class.getDeclaredField("mResources"); f.setAccessible(true); f.set(target, source); } catch (NoSuchFieldException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static void onCreate(Activity activity, Bundle savedInstanceState){ try { Method m = Activity.class.getDeclaredMethod("onCreate", new Class[]{Bundle.class}); m.setAccessible(true); m.invoke(activity, new Object[]{savedInstanceState}); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("error in onCreate", e); } } @SuppressLint("NewApi") public static void onCreate(Activity activity, Bundle savedInstanceState, PersistableBundle persistentState){ try { Method m = Activity.class.getDeclaredMethod("onCreate", new Class[]{Bundle.class, PersistableBundle.class}); m.setAccessible(true); m.invoke(activity, new Object[]{savedInstanceState,persistentState}); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("error in onCreate", e); } } public static void onPostCreate(Activity activity, Bundle savedInstanceState) { try { Method m = Activity.class.getDeclaredMethod("onPostCreate", new Class[]{Bundle.class}); m.setAccessible(true); m.invoke(activity, new Object[]{savedInstanceState}); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("error in onCreate", e); } } @SuppressLint("NewApi") public static void onPostCreate(Activity activity, Bundle savedInstanceState, PersistableBundle persistentState) { try { Method m = Activity.class.getDeclaredMethod("onPostCreate", new Class[]{Bundle.class, PersistableBundle.class}); m.setAccessible(true); m.invoke(activity, new Object[]{savedInstanceState, persistentState}); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("error in onCreate", e); } } public static void onResume(Activity activity){ try { Method m = Activity.class.getDeclaredMethod("onResume", (Class[]) null); m.setAccessible(true); m.invoke(activity, (Object[]) null); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("error in onResume", e); } } public static void onPostResume(Activity activity){ try { Method m = Activity.class.getDeclaredMethod("onPostResume", (Class[]) null); m.setAccessible(true); m.invoke(activity, (Object[]) null); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("error in onPause", e); } } public static void onPause(Activity activity){ try { Method m = Activity.class.getDeclaredMethod("onPause", (Class[]) null); m.setAccessible(true); m.invoke(activity, (Object[]) null); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("error in onPause", e); } } public static void onRestoreInstanceState(Activity activity, Bundle savedInstanceState) { try { Method m = Activity.class.getDeclaredMethod("onRestoreInstanceState", new Class[]{Bundle.class}); m.setAccessible(true); m.invoke(activity, new Object[] {savedInstanceState}); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("error in onPause", e); } } public static void onRestart(Activity activity) { try { Method m = Activity.class.getDeclaredMethod("onRestart", (Class[]) null); m.setAccessible(true); m.invoke(activity, (Object[]) null); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("error in onPause", e); } } public static void onStart(Activity activity) { try { Method m = Activity.class.getDeclaredMethod("onStart", (Class[])null); m.setAccessible(true); m.invoke(activity, (Object[])null); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("error in onStop", e); } } public static void onStop(Activity activity) { try { Method m = Activity.class.getDeclaredMethod("onStop", (Class[])null); m.setAccessible(true); m.invoke(activity, (Object[])null); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("error in onStop", e); } } public static void onDestroy(Activity activity){ try { Method m = Activity.class.getDeclaredMethod("onDestroy", (Class[])null); m.setAccessible(true); m.invoke(activity, (Object[])null); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("error in onDestroy", e); } } public static void onContextMenuClosed(Activity activity, Menu menu) { try { Method m = Activity.class.getDeclaredMethod("onContextMenuClosed", new Class[]{Menu.class}); m.setAccessible(true); m.invoke(activity, new Object[]{menu}); } catch (NoSuchMethodException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static boolean onContextItemSelected(Activity activity, MenuItem item) { try { Method m = Activity.class.getDeclaredMethod("onContextItemSelected", new Class[]{MenuItem.class}); m.setAccessible(true); return (Boolean) m.invoke(activity, new Object[]{item}); } catch (NoSuchMethodException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } return false; } public static void onCreateContextMenu(Activity activity, ContextMenu menu, View v, ContextMenuInfo menuInfo) { try { Method m = Activity.class.getDeclaredMethod("onCreateContextMenu", new Class[]{ContextMenu.class, View.class, ContextMenuInfo.class}); m.setAccessible(true); m.invoke(activity, new Object[]{menu, v, menuInfo}); } catch (NoSuchMethodException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static void onActivityResult(Activity activity, int arg0, int arg1, Intent arg2) { try { Method m = Activity.class.getDeclaredMethod("onActivityResult", new Class[]{int.class, int.class, Intent.class}); m.setAccessible(true); m.invoke(activity, new Object[]{arg0, arg1, arg2}); } catch (NoSuchMethodException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static boolean onOptionsItemSelected(Activity activity, MenuItem item) { try { Method m = Activity.class.getDeclaredMethod("onOptionsItemSelected", new Class[]{MenuItem.class}); m.setAccessible(true); return (Boolean) m.invoke(activity, new Object[]{item}); } catch (NoSuchMethodException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } return false; } public static boolean onCreateOptionsMenu(Activity activity, Menu menu) { try { Method m = Activity.class.getDeclaredMethod("onCreateOptionsMenu", new Class[]{Menu.class}); return (Boolean) m.invoke(activity, new Object[]{menu}); } catch (NoSuchMethodException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } return false; } public static Dialog onCreateDialog(Activity activity, int id, Bundle args) { try { Method m = Activity.class.getDeclaredMethod("onCreateDialog", new Class[]{ int.class, Bundle.class}); m.setAccessible(true); return (Dialog) m.invoke(activity, new Object[]{id, args}); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("error in onCreateDialog", e); } } public static Dialog onCreateDialog(Activity activity, int id) { try { Method m = Activity.class.getDeclaredMethod("onCreateDialog", new Class[]{ int.class}); m.setAccessible(true); return (Dialog) m.invoke(activity, new Object[]{id}); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("error in onCreateDialog", e); } } public static void onPrepareDialog(Activity activity, int id, Dialog dialog) { try { Method m = Activity.class.getDeclaredMethod("onPrepareDialog", new Class[]{ int.class, Dialog.class}); m.setAccessible(true); m.invoke(activity, new Object[]{id, dialog}); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("error in onPrepareDialog", e); } } public static void onPrepareDialog(Activity activity, int id, Dialog dialog, Bundle args) { try { Method m = Activity.class.getDeclaredMethod("onPrepareDialog", new Class[]{ int.class, Dialog.class, Bundle.class}); m.setAccessible(true); m.invoke(activity, new Object[]{id, dialog, args}); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("error in onPrepareDialog", e); } } public static void attach(Activity hostActivity, Activity embeddedActivity) { try { // dumpMethod(Activity.class,"attach"); Class<Object>[] parameters = new Class[]{Context.class, Class.forName("android.app.ActivityThread"), Class.forName("android.app.Instrumentation"), Class.forName("android.os.IBinder"), // not Integer.class int.class, Application.class, Intent.class, Class.forName("android.content.pm.ActivityInfo"), // Class.forName("android.os.IBinder"), CharSequence.class, Activity.class, String.class, Class.forName("android.app.Activity$NonConfigurationInstances"), Configuration.class, Class.forName("com.android.internal.app.IVoiceInteractor") }; Method m = Activity.class.getDeclaredMethod("attach", parameters); m.setAccessible(true); Object[] args = new Object[]{ hostActivity.getBaseContext(), getFiledValue(Activity.class, hostActivity, "mMainThread"), getFiledValue(Activity.class, hostActivity, "mInstrumentation"), getFiledValue(Activity.class, hostActivity, "mToken"), getFiledValue(Activity.class, hostActivity, "mIdent"), getFiledValue(Activity.class, hostActivity, "mApplication"), getFiledValue(Activity.class, hostActivity, "mIntent"), getFiledValue(Activity.class, hostActivity, "mActivityInfo"), getFiledValue(Activity.class, hostActivity, "mTitle"), getFiledValue(Activity.class, hostActivity, "mParent"), getFiledValue(Activity.class, hostActivity, "mEmbeddedID"), getFiledValue(Activity.class, hostActivity, "mLastNonConfigurationInstances"), getFiledValue(Activity.class, hostActivity, "mCurrentConfig"), null}; m.invoke(embeddedActivity, args ); } catch (NoSuchMethodException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static void attachBaseContext(Activity activity, Application application) { try { Method m = ContextWrapper.class.getDeclaredMethod("attachBaseContext", new Class[]{Context.class}); m.setAccessible(true); m.invoke(activity, new Object[]{application}); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("error in attachBaseContext", e); } } public static void copyFields(Activity host, Activity target) { String[] fields = new String[] { "mMainThread", "mInstrumentation", "mToken", "mIdent", "mApplication", "mIntent", "mActivityInfo", "mTitle", "mParent", "mEmbeddedID", "mLastNonConfigurationInstances", "mFragments",// java.lang.IllegalStateException // FragmentManagerImpl.moveToState "mWindow", "mWindowManager", "mCurrentConfig" }; copyFields(Activity.class, fields, host, target); fields = new String[] { "mThemeResource", "mTheme", "mInflater", "mOverrideConfiguration", "mResources" }; copyFields(ContextThemeWrapper.class, fields, host, target); fields = new String[] { "mBase", }; // copyFields(ContextWrapper.class, fields, host, target); // bundle should user getLayoutInflator always. try { LayoutInflater in = LayoutInflater.from(host); Field inflator = Class.forName("com.android.internal.policy.impl.PhoneWindow").getDeclaredField("mLayoutInflater"); inflator.setAccessible(true); Object winF = getFiledValue(Activity.class, host, "mWindow"); inflator.set(winF, in); } catch (NoSuchFieldException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static boolean onMenuItemSelected(Activity activity, int featureId, MenuItem menu) { try { Method m = Activity.class.getDeclaredMethod("onMenuItemSelected", new Class[]{ int.class, Menu.class}); m.setAccessible(true); return (Boolean) m.invoke(activity, new Object[]{featureId, menu}); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("error in onCreateDialog", e); } } public static boolean onPrepareOptionsPanel(Activity activity, View view, Menu menu) { try { Method m = Activity.class.getDeclaredMethod("onPrepareOptionsPanel", new Class[]{ View.class, Menu.class}); m.setAccessible(true); return (Boolean) m.invoke(activity, new Object[]{view, menu}); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("error in onCreateDialog", e); } } public static View onPreparePonCreatePanelViewanel( Activity activity, int featureId) { try { Method m = Activity.class.getDeclaredMethod("onPreparePonCreatePanelViewanel", new Class[]{ int.class}); m.setAccessible(true); return (View) m.invoke(activity, new Object[]{featureId}); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("error in onCreateDialog", e); } } public static void setApplication(Activity mTargetActivity, Application app) { try { Field field = Activity.class.getDeclaredField("mApplication"); ReflectUtil.ActivityReflectUtil.setField(mTargetActivity, field, app); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("error in setApplictivity.", e); } } public static void setBaseContext(Activity mTargetActivity, Context baseContext) { try { Field field = ContextWrapper.class.getDeclaredField("mBase"); ReflectUtil.ActivityReflectUtil.setField(mTargetActivity, field, baseContext); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("error in setBaseContext.", e); } } public static void setResource(Activity mTargetActivity, ResourcesMerger mResourceMerger) { try { Field field = ContextThemeWrapper.class.getDeclaredField("mResources"); ReflectUtil.ActivityReflectUtil.setField(mTargetActivity, field, mResourceMerger); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("error in setBaseContext.", e); } } public static void setWindowContext(Window window, Context baseContext) { try { Field field = window.getClass().getDeclaredField("Window"); ReflectUtil.ActivityReflectUtil.setField(window, field, baseContext); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("error in setWindowContext.", e); } } public static void onTitleChanged(Activity activity, CharSequence title, int color) { try { Method m = Activity.class.getDeclaredMethod("onTitleChanged", new Class[]{CharSequence.class, int.class}); m.setAccessible(true); m.invoke(activity, new Object[]{title, color}); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("error in onTitleChanged", e); } } public static void onUserLeaveHint(Activity activity) { try { Method m = Activity.class.getDeclaredMethod("onUserLeaveHint", new Class[]{}); m.setAccessible(true); m.invoke(activity, new Object[]{}); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("error in onUserLeaveHint", e); } } public static void performCreate(Activity activity, Bundle icicle) { try { Method m = Activity.class.getDeclaredMethod("performCreate", new Class[]{Bundle.class}); m.setAccessible(true); m.invoke(activity, new Object[]{icicle}); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("error in performCreate", e); } } } public static class ResourceUtil { public static int selectDefaultTheme(Resources res, int curTheme, int targetSdkVersion) { try { Method m = Class.forName(Resources.class.getCanonicalName()).getDeclaredMethod("selectDefaultTheme", new Class[]{int.class, int.class}); return (Integer) m.invoke(res, new Object[]{curTheme, targetSdkVersion}); } catch (NoSuchMethodError e) { e.printStackTrace(); } catch (NoSuchMethodException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } return -1; } } }