From 5d71204620b1511088e7b3897083ee686169caec Mon Sep 17 00:00:00 2001 From: WASDDestroy <3288211880@qq.com> Date: Mon, 3 Aug 2026 00:22:20 +0800 Subject: [PATCH 1/4] service: implement libxposed API's scope getter in ModuleServiceBridge.java --- .../moe/lovefirefly/betterzuikey/ModuleServiceBridge.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/src/main/java/moe/lovefirefly/betterzuikey/ModuleServiceBridge.java b/app/src/main/java/moe/lovefirefly/betterzuikey/ModuleServiceBridge.java index b0d38b3..2b63d1e 100644 --- a/app/src/main/java/moe/lovefirefly/betterzuikey/ModuleServiceBridge.java +++ b/app/src/main/java/moe/lovefirefly/betterzuikey/ModuleServiceBridge.java @@ -2,6 +2,8 @@ import android.util.Log; +import java.util.List; + import io.github.libxposed.service.XposedService; import io.github.libxposed.service.XposedServiceHelper; @@ -70,6 +72,11 @@ public static XposedService getService() { // -- OnServiceListener callbacks -- + public static List getScope() { + if (sService == null) return List.of(); + return sService.getScope(); + } + @Override public void onServiceBind(XposedService service) { sService = service; From ed30b5bee8d999c576e57dd2c98022e8d3885809 Mon Sep 17 00:00:00 2001 From: WASDDestroy <3288211880@qq.com> Date: Mon, 3 Aug 2026 00:23:48 +0800 Subject: [PATCH 2/4] refactor: use libxposed scope getter to fetch scope information instead of using tricky preference read --- .../lovefirefly/betterzuikey/MainActivity.kt | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/moe/lovefirefly/betterzuikey/MainActivity.kt b/app/src/main/java/moe/lovefirefly/betterzuikey/MainActivity.kt index cc495cc..79a660b 100644 --- a/app/src/main/java/moe/lovefirefly/betterzuikey/MainActivity.kt +++ b/app/src/main/java/moe/lovefirefly/betterzuikey/MainActivity.kt @@ -10,7 +10,6 @@ import androidx.viewpager2.adapter.FragmentStateAdapter import com.google.android.material.color.DynamicColors import moe.lovefirefly.betterzuikey.Config.Config import moe.lovefirefly.betterzuikey.databinding.ActivityMainBinding -import moe.lovefirefly.betterzuikey.Utils.ZuiDetector class MainActivity : AppCompatActivity() { @@ -68,7 +67,7 @@ class MainActivity : AppCompatActivity() { btn.text = getString(R.string.home_warning_copy_error) btn.setOnClickListener { val text = lastWarningMessage ?: message - val clipboard = getSystemService(android.content.Context.CLIPBOARD_SERVICE) + val clipboard = getSystemService(CLIPBOARD_SERVICE) as android.content.ClipboardManager clipboard.setPrimaryClip( android.content.ClipData.newPlainText("BetterZUIKey error", text)) @@ -248,7 +247,7 @@ class MainActivity : AppCompatActivity() { val msg = getString(R.string.agreement_body) val tv = android.widget.TextView(this).apply { - setText(msg) + text = msg setTextIsSelectable(false) setPadding(48, 32, 48, 0) setLineSpacing(4f, 1.1f) @@ -277,7 +276,7 @@ class MainActivity : AppCompatActivity() { } .setPositiveButton(getString(R.string.agreement_btn_read_doc)) { _, _ -> onAccept() - startActivity(android.content.Intent(this, HelpActivity::class.java)) + startActivity(Intent(this, HelpActivity::class.java)) } .setCancelable(false) .create() @@ -347,11 +346,9 @@ class MainActivity : AppCompatActivity() { private var sAliveConfirmed: Boolean? = null // null = not yet checked private fun statusOrdinal(): Int { - val ctx = context ?: return 3 if (sAliveConfirmed == null) { - val prefs = ctx.getSharedPreferences( - RemotePrefProvider.PREF_FILE, android.content.Context.MODE_PRIVATE) - sAliveConfirmed = prefs.getBoolean("module_active", false) + val scopeList: List = ModuleServiceBridge.getScope() + sAliveConfirmed = scopeList.all { it == "system" } } if (sAliveConfirmed == true) return if (sRootGranted) 0 else 1 @@ -482,7 +479,8 @@ class MainActivity : AppCompatActivity() { view.findViewById(R.id.tv_description)?.text = getString(R.string.home_app_description) view.findViewById(R.id.tv_project_url)?.setOnClickListener { - val intent = android.content.Intent(android.content.Intent.ACTION_VIEW, + val intent = Intent( + Intent.ACTION_VIEW, android.net.Uri.parse("https://github.com/CommandPrompt-Wang/BetterZUIKey")) startActivity(intent) } @@ -502,7 +500,7 @@ class MainActivity : AppCompatActivity() { } view.findViewById(R.id.card_help)?.setOnClickListener { - startActivity(android.content.Intent(requireContext(), HelpActivity::class.java)) + startActivity(Intent(requireContext(), HelpActivity::class.java)) } } @@ -518,7 +516,7 @@ class MainActivity : AppCompatActivity() { proc.errorStream.bufferedReader().use { it.readText() } val exit = proc.waitFor() sRootGranted = (exit == 0) - } catch (e: Exception) { + } catch (_: Exception) { sRootGranted = false } sRootChecked = true @@ -563,7 +561,7 @@ class MainActivity : AppCompatActivity() { requireContext().contentResolver.call( ConfigSyncProvider.RELOAD_URI, "setLsposedOpenRequest", null, - android.os.Bundle().apply { putBoolean("requested", true) }) + Bundle().apply { putBoolean("requested", true) }) sLastCommandOutput = "OK" view.post { if (!isAdded) return@post From 27d110f5c5c3fc67c628ea96fc187adbe165cde5 Mon Sep 17 00:00:00 2001 From: WASDDestroy <3288211880@qq.com> Date: Mon, 3 Aug 2026 00:25:20 +0800 Subject: [PATCH 3/4] refactor: remove calls to setModuleActive() in MainHook.java we no longer needs this tricky method because LSPosed is capable to report module scope via libxposed service that binds on app launch --- .../main/java/moe/lovefirefly/betterzuikey/Hook/MainHook.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/src/main/java/moe/lovefirefly/betterzuikey/Hook/MainHook.java b/app/src/main/java/moe/lovefirefly/betterzuikey/Hook/MainHook.java index f6b00b1..ec6989c 100644 --- a/app/src/main/java/moe/lovefirefly/betterzuikey/Hook/MainHook.java +++ b/app/src/main/java/moe/lovefirefly/betterzuikey/Hook/MainHook.java @@ -145,8 +145,6 @@ public void onSystemServerStarting(XposedModuleInterface.SystemServerStartingPar cfg.injectError = ""; LogHelper.log(VerboseLevel.INFO, "All hooks installed successfully!"); - // Mark module active for scope detection in the App - mConfigIPC.setModuleActive(); // Retry boot mark until the app process is up and ContentProvider responds if (!sBootMarked) { sBootMarked = true; @@ -226,7 +224,6 @@ public void run() { tries++; if (isSystem) { configIPC.sendBootMark(); - configIPC.setModuleActive(); // scope detection for App } else { configIPC.sendBootMarkApp(); } From 9d2f67a7bfee2297ad524949e757558c53e58b55 Mon Sep 17 00:00:00 2001 From: WASDDestroy <3288211880@qq.com> Date: Mon, 3 Aug 2026 00:25:50 +0800 Subject: [PATCH 4/4] refactor: remove method setModuleActive() that no longer required by scope detection --- .../betterzuikey/Hook/ConfigIPCManager.java | 25 ------------------- 1 file changed, 25 deletions(-) diff --git a/app/src/main/java/moe/lovefirefly/betterzuikey/Hook/ConfigIPCManager.java b/app/src/main/java/moe/lovefirefly/betterzuikey/Hook/ConfigIPCManager.java index 9c2ca3f..7c4ffbf 100644 --- a/app/src/main/java/moe/lovefirefly/betterzuikey/Hook/ConfigIPCManager.java +++ b/app/src/main/java/moe/lovefirefly/betterzuikey/Hook/ConfigIPCManager.java @@ -20,14 +20,6 @@ public class ConfigIPCManager { private android.content.Context mSystemContext = null; private String mLastConfigSync = ""; - /** - * Initialize ContentResolver via ActivityThread.getSystemContext() pattern - * and pull the initial config via Binder IPC. - * Must be called once after handleLoadPackage. - * - * @return the initial Config from ContentProvider, or null if unavailable. - * Caller MUST replace the file-loaded (likely default) Config with this one. - */ /** Expose resolver for direct calls (used by ESC check watcher in MainHook). */ public ContentResolver getResolver() { return mConfigResolver; } @@ -154,23 +146,6 @@ private void sendBootMarkInternal(String method) { } } - /** Write module_active flag via RemotePreferences. */ - public void setModuleActive() { - try { - if (mSystemContext == null) { - LogHelper.log(VerboseLevel.WARNING, "setModuleActive: mSystemContext is null"); - return; - } - new com.crossbowffs.remotepreferences.RemotePreferences(mSystemContext, - moe.lovefirefly.betterzuikey.BuildConfig.APPLICATION_ID + ".prefs", - moe.lovefirefly.betterzuikey.RemotePrefProvider.PREF_FILE) - .edit().putBoolean("module_active", true).apply(); - LogHelper.log(VerboseLevel.INFO, "setModuleActive: written via RemotePreferences"); - } catch (Exception e) { - LogHelper.log(VerboseLevel.WARNING, "setModuleActive failed:", e.getMessage()); - } - } - /** Read keyboard-detect Activity flag via ContentProvider (app → system_server). */ public boolean isKeyboardDetectActive() { try {