package org.bbs.apklauncher.demo;
import java.io.File;
import java.lang.reflect.Field;
import org.bbs.android.commonlib.ExceptionCatcher;
import org.bbs.apklauncher.AndroidUtil;
import org.bbs.apklauncher.ApkLauncher;
import org.bbs.apklauncher.ApkLauncherConfig;
import org.bbs.apklauncher.ApkPackageManager;
import org.bbs.apklauncher.ApkUtil;
import org.bbs.apklauncher.InstrumentationWrapper;
import org.bbs.apklauncher.LogClassLoader;
import org.bbs.apklauncher.ReflectUtil;
import org.bbs.apklauncher.ResourcesMerger;
import org.bbs.apklauncher.TargetContext;
import org.bbs.apklauncher.TargetInstrumentation;
import org.bbs.apklauncher.TargetInstrumentation.CallBack;
import org.bbs.apklauncher.emb.Host_Application;
import org.bbs.apkparser.PackageInfoX.ActivityInfoX;
import android.app.Activity;
import android.app.Application;
import android.app.Instrumentation;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Resources.Theme;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.PersistableBundle;
import android.util.Log;
public class App extends
//Application
Host_Application
{
// private static final String TARGET_PKG_NAME = "com.youku.tv";
// public static final String TARGET_LAUNCHER_NAME = "com.youku.tv.WelcomeActivity";
private static final String TARGET_PKG_NAME = "com.cibn.tv.debug";
public static final String TARGET_LAUNCHER_NAME = "com.cibn.tv.WelcomeActivity";
// private static final String TARGET_PKG_NAME = "com.example.apklauncher_app_intent_helper";
// public static final String TARGET_LAUNCHER_NAME = "com.example.apklauncher_app_intnet_helper.MainActivity";
// private static final String TARGET_PKG_NAME = "com.example.android.apis";
// public static final String TARGET_LAUNCHER_NAME = "com.example.android.apis.ApiDemos";
// private static final String TARGET_PKG_NAME = "com.example.apklauncher_zero_install";
// public static final String TARGET_LAUNCHER_NAME = "com.example.apklauncher_app.MainActivity";
private static final String TAG = App.class.getSimpleName();
public static final String APK_LAUNCHER_DIR = "apklauncher";
public App(){
super();
}
@Override
public void onCreate() {
super.onCreate();
ExceptionCatcher.attachExceptionHandler(this);
File apkDir = null;
// apkDir = getDir(APK_LAUNCHER_DIR, 0);
apkDir = new File(Environment.getExternalStorageDirectory(), "apk");
ApkLauncherConfig.setDebug(true);
ApkLauncher apk = ApkLauncher.getInstance();
apk.init(this, "plugin", false);
// ApkPackageManager.getInstance().scanApkDir(apkDir);
TargetContext.ENBABLE_FILE = false;
ApkLauncherConfig.ENALBE_SERVICE = false;
injectInstrumentation(this);
}
public void injectInstrumentation(final Application app){
try {
// inject ClassLoader
Class contextImplClass = Class.forName("android.app.ContextImpl");
Object contextImpl = AndroidUtil.getContextImpl(app);
Field packageInfoF = contextImplClass.getDeclaredField("mPackageInfo");
packageInfoF.setAccessible(true);
Object packageInfo = packageInfoF.get(contextImpl);
Field classloaderF = packageInfo.getClass().getDeclaredField("mClassLoader");
classloaderF.setAccessible(true);
ClassLoader cl = new LogClassLoader(app.getClassLoader());
ApkPackageManager apk = ApkPackageManager.getInstance();
cl = apk.createClassLoader(app, apk.getPackageInfo(TARGET_PKG_NAME));
// c = new TargetFirstClassLoader(dexPath, optimizedDirectory, libraryPath, parent, targetPackageName, hostContext)
// cl = new LogClassLoader(cl);
classloaderF.set(packageInfo, cl);
// inject Intrumentation
Field activityThreadF = contextImplClass.getDeclaredField("mMainThread");
activityThreadF.setAccessible(true);
Object activityThreadObject = activityThreadF.get(contextImpl);
Field instruF = activityThreadObject.getClass().getDeclaredField("mInstrumentation");
instruF.setAccessible(true);
Object instru = instruF.get(activityThreadObject);
Instrumentation ins = new ApkInstrumentation(app, (Instrumentation) instru, cl);
ins = new TargetInstrumentation(ins, new Handler());
((TargetInstrumentation)ins).setCallBack(new CallBack() {
@Override
public boolean onProcessIntent(Intent intent) {
ComponentName com = intent.getComponent();
if (null != com) {
String pkgName = app.getPackageName();
intent.setComponent(new ComponentName(pkgName, com.getClassName()));
}
return true;
}
});
instruF.set(activityThreadObject, ins);
} 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();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
static class ApkInstrumentation extends InstrumentationWrapper {
private static final String CLASS_NAME_CONTEXT_THEME_WRAPPER = "android.view.ContextThemeWrapper";
private ClassLoader mLoader;
private Application mApp;
private Application mTargetApp;
public ApkInstrumentation(Application app, Instrumentation base, ClassLoader apkClassLoader) {
super(base);
mApp = app;
mLoader = apkClassLoader;
}
@Override
public Activity newActivity(ClassLoader cl, String className,
Intent intent) throws InstantiationException,
IllegalAccessException, ClassNotFoundException {
if (shouldIgnore(className)) {
return super.newActivity(cl, className, intent);
}
ClassLoader targetClassLoader = mLoader;
// try init app first.
ApkPackageManager apk = ApkPackageManager.getInstance();
ActivityInfoX info = apk.getActivityInfo(className);
PackageManager pm = mApp.getPackageManager();
mTargetApp = ((Host_Application)mApp).onPrepareApplictionStub(info.applicationInfo, targetClassLoader, pm, false);
// injectBaseContext(mTargetApp);
Activity a = super.newActivity(targetClassLoader, className, intent);
ResourcesMerger r = ApkPackageManager.getTargetResource(info.applicationInfo.publicSourceDir, mApp);
try {
// inject resource
Field resF = Class.forName(CLASS_NAME_CONTEXT_THEME_WRAPPER).getDeclaredField("mResources");
resF.setAccessible(true);
resF.set(a, r);
// inject theme
int targetThemeId = ReflectUtil.ResourceUtil
.selectDefaultTheme(r,
info.theme,
info.applicationInfo.targetSdkVersion);
Log.d(TAG, "resolved activity theme: " + targetThemeId);
Theme t = r.getFirst().newTheme();
t.applyStyle(targetThemeId, true);
Field themeF = Class.forName(CLASS_NAME_CONTEXT_THEME_WRAPPER).getDeclaredField("mTheme");
themeF.setAccessible(true);
themeF.set(a, t);
} catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return a;
}
private boolean shouldIgnore(String className) {
return ApkInitActivity.class.getName().equals(className)
||BackUpActivity.class.getName().equals(className)
;
}
@Override
public void callActivityOnCreate(Activity activity, Bundle icicle) {
injectBaseContext(activity);
super.callActivityOnCreate(activity, icicle);
updateTitle(activity);
}
@Override
public void callActivityOnCreate(Activity activity, Bundle icicle,
PersistableBundle persistentState) {
injectBaseContext(activity);
super.callActivityOnCreate(activity, icicle, persistentState);
updateTitle(activity);
}
private void injectBaseContext(Object object) {
if (shouldIgnore(object.getClass().getName())) {
return;
}
try {
Field baseF = Class.forName("android.content.ContextWrapper").getDeclaredField("mBase");
baseF.setAccessible(true);
TargetContext injectContext = new TargetContext((Context) baseF.get(object));
injectContext.packageNameReady(TARGET_PKG_NAME);
injectContext.applicationContextReady(mTargetApp);
baseF.set(object, injectContext);
// inject application
ReflectUtil.ActivityReflectUtil.setActivityApplication(object, mTargetApp);
} 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();
}
}
void updateTitle(Activity activity){
if (shouldIgnore(activity.getClass().getName())) {
return;
}
ApkUtil.updateTitle(activity);
}
}
}