[黑历史] GREENIFYSHUTCUT开发经历小记(2)

· 158 words · 1 minute read

注,这篇文章是于 2023 年 6 月 15 日从最早期的 WordPress 博客迁移来的,主要是记录(证明)一下小时候折腾的各种事情吧((逃


继续昨天的文章,探索GravityBoxModPowerMenu.java

随后,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参数是菜单项触发的方法,比如说onPresscreate等,因此我们需要根据方法名判断自定义菜单项该干什么了。

String methodName = method.getName();

获得methodName之后,即可对它进行判断,我们通过Android代码(com.android.internal.policy.impl.GlobalActions.Action)可以看出接口实现了6个方法:

  1. create
  2. onPress
  3. onLongPress
  4. showDuringKeyguard
  5. showBeforeProvisioning
  6. isEnabled

首先,如果是create方法,返回View,很简单,不多说

然后如果是onPress方法,触发mHandler延时截图,也很简单。

剩下的就返回true就行了,至此代码分析完成。