From b827dd158cafdfd077c6666f8d2d3daff74c712e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=84=95=E6=99=A8HChen?= Date: Sun, 29 Dec 2024 16:22:03 +0800 Subject: [PATCH 1/2] fix: QuickBack --- .../module/hook/home/gesture/QuickBack.java | 92 +++++++++++-------- 1 file changed, 55 insertions(+), 37 deletions(-) diff --git a/app/src/main/java/com/sevtinge/hyperceiler/module/hook/home/gesture/QuickBack.java b/app/src/main/java/com/sevtinge/hyperceiler/module/hook/home/gesture/QuickBack.java index fdec9fcad..d33389a52 100644 --- a/app/src/main/java/com/sevtinge/hyperceiler/module/hook/home/gesture/QuickBack.java +++ b/app/src/main/java/com/sevtinge/hyperceiler/module/hook/home/gesture/QuickBack.java @@ -38,9 +38,23 @@ */ public class QuickBack extends BaseHC { private static final HashMap mResMap = new HashMap<>(); + private static int[] values = null; @Override protected void init() { + try { + Class mReadyStateClass = findClass("com.miui.home.recents.GestureBackArrowView$ReadyState").get(); + Enum READY_STATE_BACK = (Enum) getStaticField(mReadyStateClass, "READY_STATE_BACK"); + Enum READY_STATE_RECENT = (Enum) getStaticField(mReadyStateClass, "READY_STATE_RECENT"); + Enum READY_STATE_NONE = (Enum) getStaticField(mReadyStateClass, "READY_STATE_NONE"); + values = new int[((Object[]) callStaticMethod(mReadyStateClass, "values")).length]; + values[READY_STATE_BACK.ordinal()] = 1; + values[READY_STATE_RECENT.ordinal()] = 2; + values[READY_STATE_NONE.ordinal()] = 3; + } catch (Throwable e) { + logE(TAG, e); + } + hookMethod("com.miui.home.recents.GestureStubView", "isDisableQuickSwitch", returnResult(false) @@ -60,8 +74,16 @@ public void before() { Object getCurrentState = callMethod(mGestureBackArrowView, "getCurrentState"); int ordinal = (int) callMethod(getCurrentState, "ordinal"); - int[] mState = (int[]) getStaticField("com.miui.home.recents.GestureStubView$4", "$SwitchMap$com$miui$home$recents$GestureBackArrowView$ReadyState"); - ordinal = mState[ordinal]; + if (values == null) { + Class mGestureStubView$X = existsClass("com.miui.home.recents.GestureStubView$4") ? + findClass("com.miui.home.recents.GestureStubView$4").get() + : findClass("com.miui.home.recents.GestureStubView$5").get(); + int[] mState = (int[]) getStaticField(mGestureStubView$X, "$SwitchMap$com$miui$home$recents$GestureBackArrowView$ReadyState"); + ordinal = mState[ordinal]; + + } else + ordinal = values[ordinal]; + if (ordinal == 2) { callMethod(mGestureStubView, "onBackCancelled"); logI(TAG, "call onBackCancelled"); @@ -84,69 +106,65 @@ public void before() { Object createLoadPlan = callMethod(taskLoader, "createLoadPlan", context); callMethod(taskLoader, "preloadTasks", createLoadPlan, -1); Object taskStack = callMethod(createLoadPlan, "getTaskStack"); - ActivityOptions activityOptions = null; + if (taskStack == null || (int) callMethod(taskStack, "getTaskCount") == 0 || (runningTask = (ActivityManager.RunningTaskInfo) callMethod(recentsModel, "getRunningTask")) == null) { - setResult(null); + setResult(null); // 后台无其他任务 return; } + ArrayList stackTasks = (ArrayList) callMethod(taskStack, "getStackTasks"); - int size = stackTasks.size(); Object task = null; - int i2 = 0; - while (true) { - if (i2 >= size - 1) { + for (int i = 0; i < stackTasks.size() - 1; i++) { + Object t = stackTasks.get(i); + if ((int) getField(getField(t, "key"), "id") == runningTask.id) { + task = stackTasks.get(i + 1); break; - } else if ((int) getField(getField(stackTasks.get(i2), "key"), "id") == runningTask.id) { - task = stackTasks.get(i2 + 1); - break; - } else { - i2++; } } - if (task == null && size >= 1 && "com.miui.home".equals(runningTask.baseActivity.getPackageName())) { + if (task == null && !stackTasks.isEmpty() && "com.miui.home".equals(runningTask.baseActivity.getPackageName())) { task = stackTasks.get(0); } + if (task != null && getField(task, "icon") == null) { - setField(task, "icon", callMethod(taskLoader, "getAndUpdateActivityIcon", - getField(task, "key"), - getField(task, "taskDescription"), - context.getResources(), true - )); + setField(task, "icon", + callMethod(taskLoader, "getAndUpdateActivityIcon", + getField(task, "key"), + getField(task, "taskDescription"), + context.getResources(), + true + ) + ); } if (!(boolean) getArgs(1) || task == null) { setResult(task); return; } - int i = (int) getArgs(2); - if (i == 0) { + + ActivityOptions activityOptions = null; + int mGestureStubPos = (int) getArgs(2); + if (mGestureStubPos == 0) { activityOptions = ActivityOptions.makeCustomAnimation(context, getAnimId(context, "recents_quick_switch_left_enter"), getAnimId(context, "recents_quick_switch_left_exit")); - } else if (i == 1) { + } else if (mGestureStubPos == 1) { activityOptions = ActivityOptions.makeCustomAnimation(context, getAnimId(context, "recents_quick_switch_right_enter"), getAnimId(context, "recents_quick_switch_right_exit")); } Object iActivityManager = callStaticMethod("android.app.ActivityManagerNative", "getDefault"); if (iActivityManager != null) { - try { - if ((int) getField(getField(task, "key"), "windowingMode") == 3) { - if (activityOptions == null) { - activityOptions = ActivityOptions.makeBasic(); - } - activityOptions.getClass().getMethod("setLaunchWindowingMode", Integer.class).invoke(activityOptions, 4); + if ((int) getField(getField(task, "key"), "windowingMode") == 3) { + if (activityOptions == null) { + activityOptions = ActivityOptions.makeBasic(); } - callMethod(iActivityManager, "startActivityFromRecents", - getField(getField(task, "key"), "id"), - activityOptions == null ? null : activityOptions.toBundle()); - setResult(task); - return; - } catch (Exception e) { - logE(TAG, "Error: " + e); - setResult(task); - return; + callMethod(activityOptions, "setLaunchWindowingMode", 4); } + callMethod(iActivityManager, "startActivityFromRecents", + getField(getField(task, "key"), "id"), + activityOptions == null ? null : activityOptions.toBundle()); + setResult(task); + return; } setResult(task); } From 8672ffd51c816f4f5b867d859dbe8415a8c26f5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BB=80=E6=BC=93=E4=B8=A8Sevtinge?= <89193494+Sevtinge@users.noreply.github.com> Date: Sun, 29 Dec 2024 17:22:51 +0800 Subject: [PATCH 2/2] try to fix: clipboard list crash --- .../hook/various/clipboard/ClipboardList.java | 4 +-- .../various/clipboard/NewClipboardList.java | 34 ++++++++++++++----- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/com/sevtinge/hyperceiler/module/hook/various/clipboard/ClipboardList.java b/app/src/main/java/com/sevtinge/hyperceiler/module/hook/various/clipboard/ClipboardList.java index dffb8f486..e9a8f7e4a 100644 --- a/app/src/main/java/com/sevtinge/hyperceiler/module/hook/various/clipboard/ClipboardList.java +++ b/app/src/main/java/com/sevtinge/hyperceiler/module/hook/various/clipboard/ClipboardList.java @@ -67,8 +67,8 @@ public void init() { @Override protected void after(MethodHookParam param) { // logE(TAG, "get class: " + param.args[0]); - filePath = "/data/user/0/" + lpparam.packageName + "/files/clipboard_data.dat"; - lastFilePath = "/data/user/0/" + lpparam.packageName + "/files/last_clipboard_data_list.dat"; + filePath = lpparam.appInfo.dataDir + "/files/clipboard_data.dat"; + lastFilePath = lpparam.appInfo.dataDir + "/files/last_clipboard_data_list.dat"; // logE(TAG, "run: " + param.args[0]); getNoExpiredData((ClassLoader) param.args[0]); getView((ClassLoader) param.args[0]); diff --git a/app/src/main/java/com/sevtinge/hyperceiler/module/hook/various/clipboard/NewClipboardList.java b/app/src/main/java/com/sevtinge/hyperceiler/module/hook/various/clipboard/NewClipboardList.java index bc982221c..f78b49e25 100644 --- a/app/src/main/java/com/sevtinge/hyperceiler/module/hook/various/clipboard/NewClipboardList.java +++ b/app/src/main/java/com/sevtinge/hyperceiler/module/hook/various/clipboard/NewClipboardList.java @@ -19,11 +19,6 @@ package com.sevtinge.hyperceiler.module.hook.various.clipboard; -import static com.sevtinge.hyperceiler.utils.log.XposedLogUtils.logD; -import static com.sevtinge.hyperceiler.utils.log.XposedLogUtils.logE; -import static com.sevtinge.hyperceiler.utils.log.XposedLogUtils.logI; -import static com.sevtinge.hyperceiler.utils.log.XposedLogUtils.logW; - import android.content.ClipData; import android.content.Context; import android.net.Uri; @@ -38,10 +33,16 @@ import com.hchen.hooktool.tool.ParamTool; import com.sevtinge.hyperceiler.utils.ContentModel; import com.sevtinge.hyperceiler.utils.FileHelper; +import com.sevtinge.hyperceiler.utils.log.XposedLogUtils; + +import org.json.JSONArray; import java.util.ArrayList; import java.util.stream.Collectors; +import de.robv.android.xposed.XC_MethodHook; +import de.robv.android.xposed.XposedHelpers; + /** * 解除常用语剪贴板时间限制,条数限制和字数限制。 * from ClipboardList @@ -60,11 +61,11 @@ public class NewClipboardList extends BaseHC implements LoadInputMethodDex.OnInp public void load(ClassLoader classLoader) { mGson = new GsonBuilder().setPrettyPrinting().create(); mDataPath = lpparam.appInfo.dataDir + "/files/clipboard_data.dat"; - logI(TAG, "class loader: " + classLoader); + XposedLogUtils.logI(TAG, "class loader: " + classLoader); FileHelper.TAG = TAG; if (!FileHelper.exists(mDataPath)) { - logE(TAG, "file create failed!"); + XposedLogUtils.logE(TAG, "file create failed!"); return; } @@ -193,6 +194,23 @@ public void before() { } }) ); + XposedHelpers.findAndHookMethod("com.miui.inputmethod.MiuiClipboardManager", classLoader, "buildClipboardModelDataType", "com.miui.inputmethod.ClipboardContentModel", new XC_MethodHook() { + @Override + protected void beforeHookedMethod(MethodHookParam param) throws Throwable { + final boolean[] isSkip = {false}; + XposedHelpers.findAndHookConstructor(JSONArray.class, String.class, new XC_MethodHook() { + @Override + protected void beforeHookedMethod(MethodHookParam param) throws Throwable { + String json = (String) param.args[0]; + if (TextUtils.isEmpty(json) || json == null) { + isSkip[0] = true; + XposedLogUtils.logW(TAG, lpparam.packageName, "Got null string, skip run. String = " + param.args[0]); + } + } + }); + if (isSkip[0]) param.setResult(null); + } + }); } @@ -222,7 +240,7 @@ private void addClipboard(String add, int type, Context context) { } ArrayList readData = toContentModelList(FileHelper.read(mDataPath)); if (readData.isEmpty()) { - logW(TAG, "can't read any data!"); + XposedLogUtils.logW(TAG, "can't read any data!"); } else { if (readData.stream().anyMatch(contentModel -> contentModel.content.equals(add))) { readData.removeIf(contentModel -> contentModel.content.equals(add));