Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@
import static com.sevtinge.hyperceiler.libhook.utils.hookapi.tool.EzxHelpUtils.setBooleanField;

import android.content.Context;
import android.database.ContentObserver;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.SystemClock;
import android.provider.Settings;
import android.view.WindowInsets;
Expand All @@ -37,7 +39,7 @@
* @author 焕晨HChen
*/
public class SystemLockApp extends BaseHook {
private static final long POWER_HOLD_EXIT_MS = 3000L;
private static final long POWER_HOLD_EXIT_MS = 1000L;
private static final long SUPPRESS_POWER_MENU_AFTER_EXIT_MS = 1500L;
private static final long TRANSIENT_BLOCK_LOG_INTERVAL_MS = 1200L;

Expand All @@ -51,15 +53,15 @@
private static final String PHONE_WINDOW_MANAGER_CLASS = "com.android.server.policy.PhoneWindowManager";
private static final String MIUI_SHORTCUT_ACTIONS_CLASS = "com.miui.server.input.util.ShortCutActionsUtils";
private static final String INSETS_POLICY_CLASS = "com.android.server.wm.InsetsPolicy";
private static final String DISPLAY_POLICY_CLASS = "com.android.server.wm.DisplayPolicy";

private static final String ACTION_LONG_PRESS_POWER_KEY = "long_press_power_key";
private static final String ACTION_IMPERCEPTIBLE_PRESS_POWER_KEY = "imperceptible_press_power_key";

private Integer mGestureLineBeforeLock = null;
boolean isLock = false;
private boolean isLock = false;
private volatile long mLastPowerExitUptimeMs = 0L;
private volatile long mLastTransientBlockLogUptimeMs = 0L;
private boolean mObserverRegistered = false;

@Override
public void init() {
Expand All @@ -83,6 +85,7 @@
mLastPowerExitUptimeMs = 0L;
setLockApp(context, lockTaskId);
applyGestureLineShielding(context, true);
registerObserverIfNeeded(context);
} catch (Throwable e) {
XposedLog.e(TAG, "startSystemLockTaskMode E: " + e);
} finally {
Expand All @@ -98,10 +101,20 @@
new XposedInterface.Hooker() {
@Override
public Object intercept(XposedInterface.Chain chain) throws Throwable {
Context context = (Context) getObjectField(chain.getThisObject(), "mContext");
int callingPid = Binder.getCallingPid();

// 核心拦截逻辑:只有在锁定状态,且调用者不是系统进程自身,且没有电源键退出标志时才拦截
if (isLock && context != null && getLockApp(context) != -1) {
if (callingPid != android.os.Process.myPid() && !shouldSuppressPowerActionNow()) {

Check notice on line 109 in library/libhook/src/main/java/com/sevtinge/hyperceiler/libhook/rules/systemframework/others/SystemLockApp.java

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

library/libhook/src/main/java/com/sevtinge/hyperceiler/libhook/rules/systemframework/others/SystemLockApp.java#L109

These nested if statements could be combined
XposedLog.d(TAG, "GuidedAccess: Blocked unauthorized stopSystemLockTaskMode from PID: " + callingPid);
return null;
}
}

Object result = chain.proceed();
long identity = Binder.clearCallingIdentity();
try {
Context context = (Context) getObjectField(chain.getThisObject(), "mContext");
if (context == null) return result;

isLock = false;
Expand All @@ -117,7 +130,7 @@
}
);

// 确保 key_lock_app 和屏蔽状态一定能恢复。
// 兜底逻辑:确保内部状态清理
chainAllMethods("com.android.server.wm.ActivityTaskManagerService",
"stopLockTaskModeInternal",
new XposedInterface.Hooker() {
Expand Down Expand Up @@ -161,6 +174,24 @@
);
}

private void registerObserverIfNeeded(Context context) {
if (mObserverRegistered || context == null) return;
context.getContentResolver().registerContentObserver(
Settings.Global.getUriFor(SETTING_KEY_LOCK_APP),
false,
new ContentObserver(new Handler(context.getMainLooper())) {
@Override
public void onChange(boolean selfChange) {
if (getLockApp(context) == -1 && isLock) {
XposedLog.d(TAG, "External unlock detected, calling stopSystemLockTaskMode");
stopSystemLockTaskMode();
}
}
}
);
mObserverRegistered = true;
}

private void hookMiuiPowerLongPressTimeout() {
Class<?> ruleClass = findClassIfExists(MIUI_POWER_KEY_RULE_CLASS);
if (ruleClass != null) {
Expand All @@ -175,17 +206,12 @@
} catch (Throwable e) {
XposedLog.w(TAG, "Hook getMiuiLongPressTimeoutMs failed: " + e);
}
} else {
XposedLog.w(TAG, "Miui power key rule class not found: " + MIUI_POWER_KEY_RULE_CLASS);
}
}

private void hookMiuiPowerPostDelay() {
Class<?> policyClass = findClassIfExists(MIUI_POLICY_CLASS);
if (policyClass == null) {
XposedLog.w(TAG, "Miui policy class not found for postKeyFunction: " + MIUI_POLICY_CLASS);
return;
}
if (policyClass == null) return;

try {
findAndChainMethod(policyClass, "postKeyFunction", new XposedInterface.Hooker() {
Expand All @@ -197,12 +223,9 @@
&& !ACTION_LONG_PRESS_POWER_KEY.equals(shortcut)) {
return chain.proceed(args);
}
if (shouldSuppressPowerActionNow()) {
return null;
}
if (shouldSuppressPowerActionNow()) return null;
if (!isLock) return chain.proceed(args);

// 固定应用中统一改为 3 秒触发,并把 0.5 秒链路归并到 long_press_power_key 处理。
args[1] = (int) POWER_HOLD_EXIT_MS;
if (ACTION_IMPERCEPTIBLE_PRESS_POWER_KEY.equals(shortcut)) {
args[2] = ACTION_LONG_PRESS_POWER_KEY;
Expand All @@ -216,104 +239,66 @@
}

private void hookMiuiPowerShortcutTrigger() {
XposedInterface.Hooker triggerHooker = new XposedInterface.Hooker() {
@Override
public Object intercept(XposedInterface.Chain chain) throws Throwable {
String action = (String) chain.getArg(1);
if (!isLock && !shouldSuppressPowerActionNow()) return chain.proceed();
return interceptPowerShortcutAction(action, isLock, chain);
}
};

try {
findAndChainMethod(MIUI_SHORTCUT_ACTIONS_CLASS,
"triggerFunction",
new XposedInterface.Hooker() {
@Override
public Object intercept(XposedInterface.Chain chain) throws Throwable {
String action = (String) chain.getArg(1);
if (!isLock && !shouldSuppressPowerActionNow()) return chain.proceed();
return interceptPowerShortcutAction(action, isLock, chain);
}
},
String.class, String.class, Bundle.class, boolean.class, String.class
);
} catch (Throwable e) {
XposedLog.w(TAG, "Hook triggerFunction(5) failed: " + e);
}
findAndChainMethod(MIUI_SHORTCUT_ACTIONS_CLASS, "triggerFunction", triggerHooker,
String.class, String.class, Bundle.class, boolean.class, String.class);
} catch (Throwable ignored) {}

try {
findAndChainMethod(MIUI_SHORTCUT_ACTIONS_CLASS,
"triggerFunction",
new XposedInterface.Hooker() {
@Override
public Object intercept(XposedInterface.Chain chain) throws Throwable {
String action = (String) chain.getArg(1);
if (!isLock && !shouldSuppressPowerActionNow()) return chain.proceed();
return interceptPowerShortcutAction(action, isLock, chain);
}
},
String.class, String.class, Bundle.class, boolean.class
);
} catch (Throwable e) {
XposedLog.w(TAG, "Hook triggerFunction(4) failed: " + e);
}
findAndChainMethod(MIUI_SHORTCUT_ACTIONS_CLASS, "triggerFunction", triggerHooker,
String.class, String.class, Bundle.class, boolean.class);
} catch (Throwable ignored) {}
}

private Object interceptPowerShortcutAction(String action, boolean lockedNow, XposedInterface.Chain chain) throws Throwable {
if (ACTION_IMPERCEPTIBLE_PRESS_POWER_KEY.equals(action)) {
// 0.5s 语音/无感按压链路:仅吞掉,不退出固定应用。
return true;
}
if (ACTION_IMPERCEPTIBLE_PRESS_POWER_KEY.equals(action)) return true;
if (!ACTION_LONG_PRESS_POWER_KEY.equals(action)) return chain.proceed();
if (!lockedNow && shouldSuppressPowerActionNow()) {

if (lockedNow) {
XposedLog.d(TAG, "Power long press detected, exiting GuidedAccess");
markPowerExitAndSuppressMenuWindow();
stopSystemLockTaskMode();
return true;
}

// 3s 长按触发:沿用官方退出流程(stopSystemLockTaskMode)。
markPowerExitAndSuppressMenuWindow();
stopSystemLockTaskMode();
return true;
if (shouldSuppressPowerActionNow()) return true;
return chain.proceed();
}

private void hookSuppressPowerMenuAfterExit() {
Class<?> pwmClass = findClassIfExists(PHONE_WINDOW_MANAGER_CLASS);
if (pwmClass == null) return;

try {
chainAllMethods(pwmClass, "powerLongPress", new XposedInterface.Hooker() {
@Override
public Object intercept(XposedInterface.Chain chain) throws Throwable {
if (isLock) {
markPowerExitAndSuppressMenuWindow();
stopSystemLockTaskMode();
trySetPowerKeyHandled(chain.getThisObject(), true);
return null;
}
if (!shouldSuppressPowerActionNow()) return chain.proceed();
XposedInterface.Hooker suppressHooker = new XposedInterface.Hooker() {
@Override
public Object intercept(XposedInterface.Chain chain) throws Throwable {
if (isLock) {
markPowerExitAndSuppressMenuWindow();
stopSystemLockTaskMode();
trySetPowerKeyHandled(chain.getThisObject(), true);
return null;
}
});
} catch (Throwable e) {
XposedLog.w(TAG, "Hook powerLongPress failed: " + e);
}

try {
chainAllMethods(pwmClass, "showGlobalActions", new XposedInterface.Hooker() {
@Override
public Object intercept(XposedInterface.Chain chain) throws Throwable {
if (!shouldSuppressPowerActionNow()) return chain.proceed();
trySetPowerKeyHandled(chain.getThisObject(), true);
return null;
}
});
} catch (Throwable e) {
XposedLog.w(TAG, "Hook showGlobalActions failed: " + e);
}
if (!shouldSuppressPowerActionNow()) return chain.proceed();
trySetPowerKeyHandled(chain.getThisObject(), true);
return null;
}
};

try {
chainAllMethods(pwmClass, "showGlobalActionsInternal", new XposedInterface.Hooker() {
@Override
public Object intercept(XposedInterface.Chain chain) throws Throwable {
if (!shouldSuppressPowerActionNow()) return chain.proceed();
trySetPowerKeyHandled(chain.getThisObject(), true);
return null;
}
});
chainAllMethods(pwmClass, "powerLongPress", suppressHooker);
chainAllMethods(pwmClass, "showGlobalActions", suppressHooker);
chainAllMethods(pwmClass, "showGlobalActionsInternal", suppressHooker);
} catch (Throwable e) {
XposedLog.w(TAG, "Hook showGlobalActionsInternal failed: " + e);
XposedLog.w(TAG, "Hook PWM power actions failed: " + e);
}
}

Expand All @@ -323,39 +308,21 @@
@Override
public Object intercept(XposedInterface.Chain chain) throws Throwable {
if (!isLock || !isEnhancedShieldEnabled()) return chain.proceed();
int types = 0;
if (!chain.getArgs().isEmpty() && chain.getArg(0) instanceof Integer) {
types = (Integer) chain.getArg(0);
}
int types = (Integer) chain.getArg(0);
// 仅屏蔽导航栏的瞬时呼出,不屏蔽其他(如状态栏)
if ((types & WindowInsets.Type.navigationBars()) == 0) return chain.proceed();
debugTransientBlock("block InsetsPolicy.showTransient types=" + types);
return null;
}
});
} catch (Throwable e) {
XposedLog.w(TAG, "Hook InsetsPolicy.showTransient failed: " + e);
}

try {
chainAllMethods(DISPLAY_POLICY_CLASS, "requestTransientBars", new XposedInterface.Hooker() {
@Override
public Object intercept(XposedInterface.Chain chain) throws Throwable {
if (!isLock || !isEnhancedShieldEnabled()) return chain.proceed();
debugTransientBlock("block DisplayPolicy.requestTransientBars");
return null;
}
});
} catch (Throwable e) {
XposedLog.w(TAG, "Hook DisplayPolicy.requestTransientBars failed: " + e);
}
} catch (Throwable ignored) {}
}

private void trySetPowerKeyHandled(Object pwmObj, boolean handled) {
if (pwmObj == null) return;
try {
setBooleanField(pwmObj, "mPowerKeyHandled", handled);
} catch (Throwable ignored) {
}
} catch (Throwable ignored) {}
}

private void markPowerExitAndSuppressMenuWindow() {
Expand All @@ -382,21 +349,15 @@

private void applyGestureLineShielding(Context context, boolean enteringLockTask) {
if (context == null) return;

if (!enteringLockTask) {
restoreGestureLineState(context);
return;
}

if (!PrefsBridge.getBoolean("system_framework_guided_access_status")) return;
if (!isEnhancedShieldEnabled()) return;

try {
if (mGestureLineBeforeLock == null) {
mGestureLineBeforeLock = Settings.Global.getInt(
context.getContentResolver(),
SETTING_HIDE_GESTURE_LINE,
HIDE_GESTURE_LINE_SHOW
);
mGestureLineBeforeLock = Settings.Global.getInt(context.getContentResolver(), SETTING_HIDE_GESTURE_LINE, HIDE_GESTURE_LINE_SHOW);
}
Settings.Global.putInt(context.getContentResolver(), SETTING_HIDE_GESTURE_LINE, HIDE_GESTURE_LINE_HIDE);
} catch (Throwable e) {
Expand All @@ -405,9 +366,7 @@
}

private void restoreGestureLineState(Context context) {
if (context == null) return;
if (mGestureLineBeforeLock == null) return;

if (context == null || mGestureLineBeforeLock == null) return;
try {
Settings.Global.putInt(context.getContentResolver(), SETTING_HIDE_GESTURE_LINE, mGestureLineBeforeLock);
} catch (Throwable e) {
Expand All @@ -424,10 +383,9 @@
public int getLockApp(Context context) {
try {
return Settings.Global.getInt(context.getContentResolver(), SETTING_KEY_LOCK_APP);
} catch (Settings.SettingNotFoundException e) {
XposedLog.e(TAG, getPackageName(), "getInt hyceiler_lock_app E: " + e);
} catch (Throwable ignored) {
return -1;
}
return -1;
}

private boolean isEnhancedShieldEnabled() {
Expand All @@ -437,14 +395,12 @@
private void stopSystemLockTaskMode() {
try {
Class<?> activityTaskManager = findClassIfExists("android.app.ActivityTaskManager");
if (activityTaskManager == null) {
XposedLog.w(TAG, "ActivityTaskManager class is null");
return;
}
if (activityTaskManager == null) return;
Object service = callStaticMethod(activityTaskManager, "getService");
// 这里我们显式地让系统知道我们想要停止锁定
callMethod(service, "stopSystemLockTaskMode");
} catch (Throwable e) {
XposedLog.e(TAG, "Power hold exit lock task E: " + e);
XposedLog.e(TAG, "stopSystemLockTaskMode helper E: " + e);
}
}
}
Loading
Loading