注,这篇文章是于 2023 年 6 月 15 日从最早期的 WordPress 博客迁移来的,主要是记录(证明)一下小时候折腾的各种事情吧((逃
随后,hook globalActionClass中的createDialog函数,它负责创建一个对话框并返回,对话框的所有配置都是这个方法构造的,它最终会返回一个AlertDialog,即关机对话框,类似于以下方法:
private AlertDialog create() {// 构造一个对话框
…..(比如说设置对话框的标题)
return dialog;
}
gravitybox代码:
XposedHelpers.findAndHookMethod(globalActionsClass, “createDialog”, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(final MethodHookParam param) throws Throwable {
// 目标函数执行前
}
@Override
protected void afterHookedMethod(final MethodHookParam param) throws Throwable {
//目标函数执行后
}
在beforeHookedMethod中,重力工具箱判断 重启菜单是否已经被hook, 如果是,则清除(unhook),以便下面执行。
在afterHookedMethod中,找到关机菜单的List以及Adapter,类似于listview的adapter,这个也如此。
List<Object> mItems = (List<Object>) XposedHelpers.getObjectField(param.thisObject, “mItems”);
BaseAdapter mAdapter = (BaseAdapter) XposedHelpers.getObjectField(param.thisObject, “mAdapter”);
int index = 1;
找到了这些,随后即可读取配置文件对列表进行修改,完成后**mAdapter.notifyDataSetChanged();**通知修改即可。
添加项目 #
我以添加截图为例子,介绍重力工具箱是如何添加自定义项目到关机菜单的。
在刚刚的afterHookedMethod中已经找到了目标list以及adapter,判断用户配置是否允许添加截图菜单项,如果是,添加:
// Add screenshot action if enabled
if (prefs.getBoolean(GravityBoxSettings.PREF_KEY_POWERMENU_SCREENSHOT, false)) {
if (mScreenshotAction == null) {
mScreenshotAction = Proxy.newProxyInstance(classLoader, new Class<?>[] { actionClass },
new ScreenshotAction(mHandler));
if (DEBUG) log(“mScreenshotAction created”);
}
mItems.add(index++, mScreenshotAction);
}
关键是这两句:
初始化截图菜单项
mScreenshotAction = Proxy.newProxyInstance(classLoader, new Class<?>[] { actionClass },
new ScreenshotAction(mHandler));
往list中添加
mItems.add(index++, mScreenshotAction);
添加很简单,我们主要看看它是如何初始化的。
上面为什么用Proxy.newProxyInstance我还不太明白。
使用new Class>[] { actionClass }来调用上一篇文章我们讲的actionClass,即 关机菜单项的操作接口,实现了一些处理菜单项事件的方法,我们的自定义方法也需要继承该接口。
随后new ScreenshotAction(mHandler)初始化内部类ScreenshotAction,处理菜单项事件。
ScreenshotAction #
这是ModPowerMenu的内部类,继承InvocationHandler接口,实际上也就是刚刚通过Proxy.newProxyInstance生成的actionClass接口,模拟一个系统的菜单项。
处理事件的方法是public Object invoke(Object proxy, Method method, Object[] args),其中的method参数是菜单项触发的方法,比如说onPress,create等,因此我们需要根据方法名判断自定义菜单项该干什么了。
String methodName = method.getName();
获得methodName之后,即可对它进行判断,我们通过Android代码(com.android.internal.policy.impl.GlobalActions.Action)可以看出接口实现了6个方法:
- create
- onPress
- onLongPress
- showDuringKeyguard
- showBeforeProvisioning
- isEnabled
首先,如果是create方法,返回View,很简单,不多说
然后如果是onPress方法,触发mHandler延时截图,也很简单。
剩下的就返回true就行了,至此代码分析完成。