/*
* Copyright (C) 2015 HouKx <hkx.aidream@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.pluginmgr;
import java.io.File;
import java.lang.reflect.Field;
import android.app.Activity;
import android.content.ComponentName;
import android.content.ContextWrapper;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.ActivityInfo;
import android.content.res.AssetManager;
import android.os.Bundle;
import android.util.Log;
import android.view.Window;
/**
* 提供公共方法供自动生成的Activity调用
*
* @author HouKangxi
*/
public class ActivityOverider {
private static final String tag = "ActivityOverider";
/**
* 自动生成的 Activity 的全类名
*/
static final String targetClassName = "androidx.pluginmgr.PluginActivity";
// ------------------- process service ---------
/**
* 覆盖 StarService 方法
*
* @param intent
* @param fromAct
*/
public static ComponentName overrideStartService(Activity fromAct,
String pluginId, Intent intent) {
// TODO 覆盖 StarService 方法
Log.d(tag, "overrideStartService");
return fromAct.startService(intent);
}
public static boolean overrideBindService(Activity fromAct,
String pluginId, Intent intent, ServiceConnection conn, int flags) {
// TODO overrideBindService
Log.d(tag, "overrideBindService");
return fromAct.bindService(intent, conn, flags);
}
public static void overrideUnbindService(Activity fromAct, String pluginId,
ServiceConnection conn) {
// TODO overrideUnbindService
Log.d(tag, "overrideUnbindService");
fromAct.unbindService(conn);
}
public static boolean overrideStopService(Activity fromAct,
String pluginId, Intent intent) {
// TODO overrideStopService
Log.d(tag, "overrideStopService");
return fromAct.stopService(intent);
}
// ------------------ process Activity ---------------------------
/**
* 处理 插件Activity 通过 intent 跳转到别的Activity
* <p>
* 供插件中的 startActivity 调用
*
* @param fromAct
* - 发出请求的Activity
* @param pluginId
* - 插件id
* @param intent
* - 启动其他Activity的Intent请求
* @param requestCode
* @param options
* @return 修改后的 Intent
*/
public static Intent overrideStartActivityForResult(Activity fromAct,
String pluginId, Intent intent, int requestCode, Bundle options) {
// 主要做以下工作:
// 1 、修改Intent的跳转目标
// 2 、帮助插件类加载器决定使用哪个activity类加载器
PluginManager mgr = PluginManager.getInstance();
// 优先判断类名,若类名为空再判断 Action
if (intent.getComponent() != null
&& intent.getComponent().getClassName() != null) {
// action 为空,但是指定了包名和 activity类名
ComponentName compname = intent.getComponent();
String pkg = compname.getPackageName();
String toActName = compname.getClassName();
PlugInfo thisPlugin = mgr.getPluginById(pluginId);
ActivityInfo actInThisApk = null;
if (pkg != null) {
if (pkg.equals(thisPlugin.getPackageName())) {
actInThisApk = thisPlugin
.findActivityByClassName(toActName);
}
} else {
actInThisApk = thisPlugin.findActivityByClassName(toActName);
}
if (actInThisApk != null) {
setPluginIntent(intent, thisPlugin, actInThisApk.name);
} else {
for (PlugInfo plugInfo : mgr.getPlugins()) {
if (plugInfo == thisPlugin) {
continue;
}
ActivityInfo otherAct = plugInfo
.findActivityByClassName(toActName);
if (otherAct != null) {
setPluginIntent(intent, plugInfo, otherAct.name);
break;
}
}
}
} else if (intent.getAction() != null) {
String action = intent.getAction();
//
// 开始处理 action
// 先判断activity所在的插件有没有对应action,因为绝大多数情况下应用都是在其内部界面之间跳转
PlugInfo thisPlugin = mgr.getPluginById(pluginId);
ActivityInfo actInThisApk = thisPlugin.findActivityByAction(action);
if (actInThisApk != null) {
setPluginIntent(intent, thisPlugin, actInThisApk.name);
} else {
for (PlugInfo plugInfo : mgr.getPlugins()) {
if (plugInfo == thisPlugin) {
continue;
}
ActivityInfo otherAct = plugInfo
.findActivityByAction(action);
if (otherAct != null) {
setPluginIntent(intent, plugInfo, otherAct.name);
break;
}
}
}
}
return intent;
}
private static void setPluginIntent(Intent intent, PlugInfo plugin,
String actName) {
PluginManager mgr = PluginManager.getInstance();
String pluginId = plugin.getId();
createProxyDex(plugin, actName);
String act = mgr.getFrameworkClassLoader().newActivityClassName(
pluginId, actName);
ComponentName compname = new ComponentName(mgr.getContext(), act);
intent.setComponent(compname);
}
static File getPluginBaseDir(String pluginId) {
String pluginPath = PluginManager.getInstance()
.getDexInternalStoragePath().getAbsolutePath();
String pluginDir = pluginPath + '/' + pluginId + "-dir/";
File folder = new File(pluginDir);
folder.mkdirs();
return folder;
}
static File getPluginLibDir(String pluginId) {
File folder = new File(getPluginBaseDir(pluginId) + "/lib/");
return folder;
}
static File getPorxyActivityDexPath(String pluginId, String activity) {
File folder = new File(getPluginBaseDir(pluginId) + "/activities/");
folder.mkdirs();
String suffix = ".dex";
if (android.os.Build.VERSION.SDK_INT < 11) {
suffix = ".jar";
}
File savePath = new File(folder, activity + suffix);
return savePath;
}
static File createProxyDex(PlugInfo plugin, String activity) {
return createProxyDex(plugin, activity, true);
}
static File createProxyDex(PlugInfo plugin, String activity, boolean lazy) {
File savePath = getPorxyActivityDexPath(plugin.getId(), activity);
createProxyDex(plugin, activity, savePath, lazy);
return savePath;
}
private static void createProxyDex(PlugInfo plugin, String activity,
File saveDir, boolean lazy) {
// Log.d(tag + ":createProxyDex", "plugin=" + plugin + "\n, activity="
// + activity);
if (lazy && saveDir.exists()) {
// Log.d(tag, "dex alreay exists: " + saveDir);
// 已经存在就不创建了,直接返回
return;
}
// Log.d(tag, "actName=" + actName + ", saveDir=" + saveDir);
try {
String pkgName = plugin.getPackageName();
ActivityClassGenerator.createActivityDex(activity, targetClassName,
saveDir, plugin.getId(), pkgName);
} catch (Throwable e) {
Log.e(tag, Log.getStackTraceString(e));
}
}
/**
* 按照pluginId寻找AssetManager
* <p>
* 供插件中的 onCreate()方法内 (super.onCreate()之前)调用 <br/>
* 到了这里可以说框架已经成功创建了activity
*
* @param pluginId
* -插件Id
* @param fromAct
* - 发出请求的Activity
* @return
*/
public static AssetManager getAssetManager(String pluginId, Activity fromAct) {
PlugInfo rsinfo = PluginManager.getInstance().getPluginById(pluginId);
// fromAct.getApplicationContext();
try {
Field f = ContextWrapper.class.getDeclaredField("mBase");
f.setAccessible(true);
f.set(fromAct, rsinfo.getApplication());
} catch (Exception e) {
Log.e(tag, Log.getStackTraceString(e));
}
// 如果是三星Galaxy S4 手机,则使用包装的LayoutInflater替换原LayoutInflater
// 这款手机在解析内置的布局文件时有各种错误
if (android.os.Build.MODEL.equals("GT-I9500")) {
Window window = fromAct.getWindow();// 得到 PhoneWindow 实例
try {
ReflectionUtils.setFieldValue(window, "mLayoutInflater",
new LayoutInflaterWrapper(window.getLayoutInflater()));
} catch (Exception e) {
Log.e(tag, Log.getStackTraceString(e));
}
}
return rsinfo.getAssetManager();
}
/**
* 按下back键的方法调用
*
* @param pluginId
* @param fromAct
* @return 是否调用父类的onBackPressed()方法
*/
public static boolean overrideOnbackPressed(Activity fromAct,
String pluginId) {
PlugInfo plinfo = PluginManager.getInstance().getPluginById(pluginId);
String actName = fromAct.getClass().getSuperclass().getName();
ActivityInfo actInfo = plinfo.findActivityByClassName(actName);
boolean finish = plinfo.isFinishActivityOnbackPressed(actInfo);
if (finish) {
fromAct.finish();
}
boolean ivsuper = plinfo.isInvokeSuperOnbackPressed(actInfo);
Log.d(tag, "finish? " + finish + ", ivsuper? " + ivsuper);
return ivsuper;
}
//
// =================== Activity 生命周期回调方法 ==================
//
public static void callback_onCreate(String pluginId, Activity fromAct) {
PluginManager con = PluginManager.getInstance();
// setTheme
PlugInfo plugin = con.getPluginById(pluginId);
String actName = fromAct.getClass().getSuperclass().getName();
Log.d(tag, "pluginId = " + plugin + ", actName = " + actName
+ ", simpleName="
+ fromAct.getClass().getSuperclass().getSimpleName());
ActivityInfo actInfo = plugin.findActivityByClassName(actName);
int themeResId = actInfo.theme;
Log.d(tag, "actTheme=" + themeResId);
if (themeResId == 0) {
themeResId = plugin.getPackageInfo().applicationInfo.theme;
Log.d(tag, "applicationTheme=" + themeResId);
}
if (themeResId != 0) {
fromAct.setTheme(themeResId);
}
// invoke callback
PluginActivityLifeCycleCallback callback = con
.getPluginActivityLifeCycleCallback();
if (callback != null) {
callback.onCreate(pluginId, fromAct);
}
}
public static void callback_onResume(String pluginId, Activity fromAct) {
PluginActivityLifeCycleCallback callback = PluginManager.getInstance()
.getPluginActivityLifeCycleCallback();
if (callback != null) {
callback.onResume(pluginId, fromAct);
}
}
public static void callback_onStart(String pluginId, Activity fromAct) {
PluginActivityLifeCycleCallback callback = PluginManager.getInstance()
.getPluginActivityLifeCycleCallback();
if (callback != null) {
callback.onStart(pluginId, fromAct);
}
}
public static void callback_onRestart(String pluginId, Activity fromAct) {
PluginActivityLifeCycleCallback callback = PluginManager.getInstance()
.getPluginActivityLifeCycleCallback();
if (callback != null) {
callback.onRestart(pluginId, fromAct);
}
}
public static void callback_onPause(String pluginId, Activity fromAct) {
PluginActivityLifeCycleCallback callback = PluginManager.getInstance()
.getPluginActivityLifeCycleCallback();
if (callback != null) {
callback.onPause(pluginId, fromAct);
}
}
public static void callback_onStop(String pluginId, Activity fromAct) {
PluginActivityLifeCycleCallback callback = PluginManager.getInstance()
.getPluginActivityLifeCycleCallback();
if (callback != null) {
callback.onStop(pluginId, fromAct);
}
}
public static void callback_onDestroy(String pluginId, Activity fromAct) {
PluginActivityLifeCycleCallback callback = PluginManager.getInstance()
.getPluginActivityLifeCycleCallback();
if (callback != null) {
callback.onDestroy(pluginId, fromAct);
}
}
}