package loon.apk.shell;
import android.app.Activity;
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.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.os.Build;
import android.os.Bundle;
import android.os.Looper;
import android.view.KeyEvent;
import android.widget.Toast;
import java.io.File;
import java.io.IOException;
import dalvik.system.DexClassLoader;
public abstract class APKShellActivity extends Activity implements APKProxy {
private APKObject apk_object;
private boolean error = false;
private APKSetting setting;
public void register(APKSetting set) {
this.setting = set;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
this.onMain();
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread thread, final Throwable ex) {
ex.printStackTrace();
try {
final Context context = APKReflect
.in("android.app.ActivityThread")
.call("currentActivityThread")
.call("getSystemContext").get();
new Thread() {
@Override
public void run() {
Looper.prepare();
Toast.makeText(context, "Data Error!",
Toast.LENGTH_SHORT).show();
Looper.loop();
}
}.start();
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
}
Thread.setDefaultUncaughtExceptionHandler(Thread
.getDefaultUncaughtExceptionHandler());
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(0);
} catch (Exception exce) {
exce.printStackTrace();
}
}
});
super.onCreate(savedInstanceState);
apk_object = loadAPK(APKShellActivity.this, setting.apkPath, false);
apk_object.setTopActivityName(setting.apkActivityName);
if (!apk_object.isAPKInit()) {
fillAPK(apk_object);
}
if (!apk_object.isAPKInit()) {
throw new APKCreateFailedException("Create APK failed!");
}
try {
APKActivityControl control = new APKActivityControl(
APKShellActivity.this, apk_object.getCurrentAPKActivity(),
apk_object.getAPKApplication(), setting);
apk_object.setControl(control);
control.dispatchProxyToAPK();
APKReflect.in(apk_object.getCurrentAPKActivity()).call(
"attachBaseContext", this);
control.runOnCreate(savedInstanceState);
APKCallbacks.runAllOnCreate(savedInstanceState);
} catch (Exception e) {
error = true;
processError(e);
}
}
public abstract void onMain();
private void processError(Exception ex) {
}
@Override
public Resources getResources() {
if (apk_object == null) {
return super.getResources();
}
return apk_object.getAPKRes() == null ? super.getResources()
: apk_object.getAPKRes();
}
@Override
public Resources.Theme getTheme() {
if (apk_object == null) {
return super.getTheme();
}
return apk_object.getCurrentAPKTheme() == null ? super.getTheme()
: apk_object.getCurrentAPKTheme();
}
@Override
public AssetManager getAssets() {
if (apk_object == null) {
return super.getAssets();
}
return apk_object.getAPKAssetManager() == null ? super.getAssets()
: apk_object.getAPKAssetManager();
}
@Override
public ClassLoader getClassLoader() {
if (apk_object == null) {
return super.getClassLoader();
}
if (apk_object.isAPKInit()) {
return apk_object.getAPKLoader();
}
return super.getClassLoader();
}
@Override
protected void onResume() {
super.onResume();
if (apk_object == null) {
return;
}
APKActivityCallback caller = apk_object.getControl();
if (caller != null) {
caller.runOnResume();
APKCallbacks.runAllOnResume();
}
}
@Override
protected void onStart() {
super.onStart();
if (apk_object == null) {
return;
}
APKActivityCallback caller = apk_object.getControl();
if (caller != null) {
try {
caller.runOnStop();
APKCallbacks.runAllOnStop();
} catch (Exception e) {
error = true;
processError(e);
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (apk_object == null) {
return;
}
APKActivityCallback caller = apk_object.getControl();
if (caller != null) {
if (!error) {
try {
caller.runOnDestroy();
APKCallbacks.runAllOnDestroy();
} catch (Exception e) {
error = true;
processError(e);
}
}
}
}
@Override
protected void onPause() {
super.onPause();
if (apk_object == null) {
return;
}
APKActivityCallback caller = apk_object.getControl();
if (caller != null) {
if (!error) {
try {
caller.runOnPause();
APKCallbacks.runAllOnPause();
} catch (Exception e) {
error = true;
processError(e);
}
}
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (apk_object == null) {
return;
}
APKActivityCallback caller = apk_object.getControl();
if (caller != null) {
if (!error) {
try {
caller.runOnSaveInstanceState(outState);
APKCallbacks.runAllOnSaveInstanceState(outState);
} catch (Exception e) {
error = true;
processError(e);
}
}
}
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
if (apk_object == null) {
return;
}
APKActivityCallback caller = apk_object.getControl();
if (caller != null) {
if (!error) {
try {
caller.runOnRestoreInstanceState(savedInstanceState);
APKCallbacks
.runAllOnRestoreInstanceState(savedInstanceState);
} catch (Exception e) {
error = true;
processError(e);
}
}
}
}
@Override
public APKObject loadAPK(Activity ctx, String apkPath) {
return loadAPK(ctx, apkPath, true);
}
@Override
public APKObject loadAPK(Activity ctx, String apkPath, boolean checkInit) {
APKObject apkobj = APKManager.loadAPK(ctx, apkPath);
if (checkInit) {
if (!apkobj.isAPKInit()) {
fillAPK(apkobj);
}
}
return apkobj;
}
@Override
public APKObject loadAPK(Activity ctx, String apkPath, String activityName) {
APKObject apkobj = loadAPK(ctx, apkPath, false);
apkobj.setTopActivityName(activityName);
fillAPK(apkobj);
return apkobj;
}
@Override
public APKObject loadAPK(Activity ctx, String apkPath, int index) {
APKObject apkobj = loadAPK(ctx, apkPath, false);
if (apkobj.isAPKInit()) {
apkobj.setTopActivityName(apkobj.getActivityInfos()[index].name);
fillAPK(apkobj);
} else {
try {
PackageInfo info = APKTools.getAppInfo(this, apkPath);
String name = info.activities[index].name;
apkobj.setTopActivityName(name);
fillAPK(apkobj);
} catch (PackageManager.NameNotFoundException e) {
throw new RuntimeException();
}
}
return apkobj;
}
@Override
public void fillAPK(APKObject apkobj) {
if (apkobj == null) {
throw new RuntimeException("APKObject is null !");
}
String apkPath = apkobj.getAPKPath();
File file = new File(getFilesDir(), apkPath);
if (!file.exists()) {
try {
APKTools.retrieveFromAssets(this, apkPath);
} catch (IOException e) {
}
}
File apk = new File(file.getAbsolutePath());
if (!apk.exists()) {
throw new APKNotFoundException(apkPath);
}
apkPath = apk.getAbsolutePath();
apkobj.setAPKPath(apkPath);
apk = null;
putAPKRes(apkobj);
if (!apkobj.isCompleted()) {
putAPKInfo(apkobj);
}
try {
putAPKLoader(apkobj);
putAPKTheme(apkobj);
putAPKApplication(apkobj);
} catch (Exception ex) {
ex.printStackTrace();
}
}
private void putAPKTheme(APKObject apkobj) {
PackageInfo packageInfo = apkobj.getAPKPkgInfo();
String mClass = apkobj.getTopActivityName();
int defaultTheme = packageInfo.applicationInfo.theme;
ActivityInfo curActivityInfo = null;
for (ActivityInfo a : packageInfo.activities) {
if (a.name.equals(mClass)) {
curActivityInfo = a;
if (a.theme != 0) {
defaultTheme = a.theme;
} else if (defaultTheme != 0) {
} else {
if (Build.VERSION.SDK_INT >= 14) {
defaultTheme = android.R.style.Theme_DeviceDefault;
} else {
defaultTheme = android.R.style.Theme;
}
}
break;
}
}
apkobj.getCurrentAPKTheme().applyStyle(defaultTheme, true);
setTheme(defaultTheme);
if (curActivityInfo != null) {
getWindow().setSoftInputMode(curActivityInfo.softInputMode);
}
}
private void putAPKApplication(APKObject apkobj) {
String appName = apkobj.getAppName();
if (appName == null) {
return;
}
if (appName.isEmpty()) {
return;
}
ClassLoader loader = apkobj.getAPKLoader();
if (loader == null)
throw new APKCreateFailedException();
try {
Application APKApp = (Application) loader.loadClass(appName)
.newInstance();
try {
APKReflect.in(APKApp).call("attach", getApplicationContext());
} catch (Exception e) {
e.printStackTrace();
}
apkobj.bindAPKApp(APKApp);
} catch (InstantiationException e) {
} catch (IllegalAccessException e) {
} catch (ClassNotFoundException e) {
}
}
private void putAPKLoader(APKObject apkobj) throws IOException {
DexClassLoader loader = APKDexLoader.getClassLoader(
apkobj.getAPKPath(), this, getClassLoader());
apkobj.setAPKLoader(loader);
String top = apkobj.getTopActivityName();
if (top == null) {
top = apkobj.getActivityInfos()[0].name;
apkobj.setTopActivityName(top);
}
try {
Activity myAPK = (Activity) apkobj.getAPKLoader()
.loadClass(apkobj.getTopActivityName()).newInstance();
apkobj.setCurrentAPKActivity(myAPK);
} catch (Exception e) {
throw new RuntimeException(e.getMessage());
}
}
private void putAPKInfo(APKObject apkobj) {
PackageInfo info = null;
try {
info = APKTools.getAppInfo(this, apkobj.getAPKPath());
} catch (PackageManager.NameNotFoundException e) {
throw new RuntimeException(apkobj.getAPKPath());
}
if (info == null) {
throw new APKCreateFailedException("Create APK from "
+ apkobj.getAPKPath());
}
apkobj.setAPKPkgInfo(info);
apkobj.setAppName(info.applicationInfo.className);
apkobj.setCompleted(true);
}
private void putAPKRes(APKObject apkobj) {
try {
AssetManager assetManager = AssetManager.class.newInstance();
APKReflect assetRef = APKReflect.in(assetManager);
assetRef.call("addAssetPath", apkobj.getAPKPath());
apkobj.setAPKAssetManager(assetManager);
Resources superRes = super.getResources();
Resources APKRes = new Resources(assetManager,
superRes.getDisplayMetrics(), superRes.getConfiguration());
apkobj.setAPKRes(APKRes);
Resources.Theme APKTheme = apkobj.getAPKRes().newTheme();
APKTheme.setTo(super.getTheme());
apkobj.setCurrentAPKTheme(APKTheme);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onBackPressed() {
if (apk_object == null || error) {
super.onBackPressed();
}
APKActivityCallback caller = apk_object.getControl();
if (caller != null) {
try {
caller.runOnBackPressed();
APKCallbacks.runAllOnBackPressed();
} catch (Exception e) {
error = true;
processError(e);
}
}
}
@Override
protected void onStop() {
super.onStop();
if (apk_object == null) {
return;
}
APKActivityCallback caller = apk_object.getControl();
if (caller != null) {
if (!error) {
try {
caller.runOnStop();
APKCallbacks.runAllOnStop();
} catch (Exception e) {
error = true;
processError(e);
}
}
}
}
@Override
protected void onRestart() {
super.onRestart();
if (apk_object == null) {
return;
}
APKActivityCallback caller = apk_object.getControl();
if (caller != null) {
try {
caller.runOnRestart();
APKCallbacks.runAllOnRestart();
} catch (Exception e) {
error = true;
processError(e);
}
}
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (apk_object == null) {
return super.onKeyDown(keyCode, event);
}
APKActivityCallback caller = apk_object.getControl();
if (caller != null) {
if (!error) {
APKCallbacks.runAllOnKeyDown(keyCode, event);
return caller.runOnKeyDown(keyCode, event);
}
}
return super.onKeyDown(keyCode, event);
}
@Override
public ComponentName startService(Intent service) {
service.setClass(this, APKServiceProxy.class);
String className = service.getComponent().getClassName();
apk_object.setCurrentServiceClassName(className);
return super.startService(service);
}
}