package org.bbs.apklauncher;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.bbs.apklauncher.api.ExportApi;
import org.bbs.apklauncher.emb.IntentHelper;
import org.bbs.apkparser.PackageInfoX;
import org.bbs.apkparser.PackageInfoX.ActivityInfoX;
import android.app.Application;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ResolveInfo;
import android.os.AsyncTask;
import android.text.TextUtils;
import android.util.Log;
/**
* @author bysong
*
*/
@ExportApi
public class ApkLauncher {
private static final String TAG = ApkLauncher.class.getSimpleName();
public static final String ASSET_PLUGIN_DIR = "plugin";
public static final String EXTRA_TARGET_COMPONENT_CLASS_NAME = "EXTRA_TARGET_COMPONENT_CLASS_NAME";
public static final String EXTRA_HOST_COMPONENT_CLASS_NAME = "EXTRA_HOST_COMPONENT_CLASS_NAME";
public static final String MANIFEST_META_REQUIRE_MIN_SDK_VERSION = "apklauncher.min.sdk.version";
private Map<String, String> mT2HMap;
private static ApkLauncher sInstance;
public static ApkLauncher getInstance(){
if (sInstance == null) {
sInstance = new ApkLauncher();
}
return sInstance;
}
private OnProcessIntent mListener;
private ApkLauncher() {
mT2HMap = new HashMap<String, String>();
}
public void init(Application context, String assetsPath, boolean overwrite){
ApkPackageManager.getInstance().init(context, assetsPath, overwrite);
}
public void initAsync(final Application context, final String assetsPath, final boolean overwrite, final InitCallBack callback){
new AsyncTask<Void, Void, Void>(){
@Override
protected Void doInBackground(Void... params) {
init(context, assetsPath, overwrite);
return null;
}
protected void onPostExecute(Void result) {
if (callback != null){
callback.onInited();
}
};
}.execute();
}
public void setT2HMap(TKey key, String hostStubClassName){
mT2HMap.put(key.key(), hostStubClassName);
}
public void setOnProcessIntentCallback(OnProcessIntent listener){
mListener = listener;
}
public boolean onProcessIntent(Intent intent, ClassLoader targetClassLoader, Context hostContext) {
if (mListener != null && mListener.onProcessStartActivityIntent(intent, targetClassLoader, hostContext)) {
return true;
}
Log.i(TAG, "processIntent. intent: " + intent);
List<ResolveInfo> acts = ApkPackageManager.getInstance().queryIntentActivities(intent, 0);
if (acts.size() > 0) {
Log.i(TAG, "intent matchs a installed plugin.");
ActivityInfo aInfo = acts.get(0).activityInfo;
// may be we need a new classloader.
targetClassLoader = ApkPackageManager.getInstance().createClassLoader(hostContext, ((ActivityInfoX)aInfo).mPackageInfo);
prepareIntent(intent, targetClassLoader, hostContext, aInfo.name);
return true;
} else {
Log.w(TAG, "can not handle intent: " + intent);
return false;
}
}
// inject new stub class name
public void prepareIntent(Intent intent, ClassLoader targetClassLoader,
Context hostContext, String targetClassName) {
ComponentName com;
String superClassName = ApkUtil.getSuperClassName(targetClassLoader, targetClassName);
String hostClassName = targetStubtoHostStubClassName(superClassName);
com = new ComponentName(hostContext.getPackageName(), hostClassName);
// inject and replace with our component.
intent.setComponent(com);
ActivityInfoX a = ApkPackageManager.getInstance().getActivityInfo(targetClassName);
if (a != null) {
intent.putExtra(EXTRA_TARGET_COMPONENT_CLASS_NAME, a.name);
intent.putExtra(EXTRA_HOST_COMPONENT_CLASS_NAME, hostClassName);
}
}
public void startActivity(Context context, PackageInfoX.ActivityInfoX a) {
ClassLoader cl = ApkPackageManager.getInstance().createClassLoader(context, a.mPackageInfo);
startActivity(context, cl, a);
}
public void startActivity(Context context, ClassLoader classloader, PackageInfoX.ActivityInfoX a) {
if (null == a) {
throw new RuntimeException("activity info in null");
}
Intent launcher = new Intent();
launcher.setComponent(new ComponentName(a.packageName, a.name));
onProcessIntent(launcher, classloader, context);
launcher.putExtra(IntentHelper.EXTRA_INJECT, false);
context.startActivity(launcher);
}
private String targetStubtoHostStubClassName(String targetStubClass) {
if (mT2HMap.containsKey(targetStubClass)){
return mT2HMap.get(targetStubClass);
}
return targetStubClass.replace("Target", "Stub");
}
public static interface OnProcessIntent {
public boolean onProcessStartActivityIntent(Intent intent, ClassLoader targetClassLoader, Context hostContext);
}
public static enum TKey {
ACTIVITY ("org.bbs.apklauncher.emb.auto_gen.Target_Activity"),
ACTIVITY_GROUP ("org.bbs.apklauncher.emb.auto_gen.Target_ActivityGroup"),
EXPENDABLE_ACTIVITY("org.bbs.apklauncher.emb.auto_gen.Target_ActivityGroup"),
LIST_ACTIVITY ("org.bbs.apklauncher.emb.auto_gen.Target_ListActivity"),
FRAGMENT_ACTIVITY ("org.bbs.apklauncher.emb.auto_gen.Target_FragmentActivity"),
ACTIONBAR_ACTIVITY ("org.bbs.apklauncher.emb.auto_gen.Target_ActionBarActivity"),
PREFERENCE_ACTIVITY("org.bbs.apklauncher.emb.auto_gen.Target_PreferenceActivity"),
TAB_ACTIVITY ("org.bbs.apklauncher.emb.auto_gen.Target_TabActivity");
private String mKey;
private TKey(String key){
mKey = key;
}
public String key(){
return mKey;
}
}
public static interface InitCallBack{
public void onInited();
}
}