Clean up navigation module code

This commit is contained in:
ajp_anton
2026-06-22 01:11:33 +00:00
parent 0956bbc4d7
commit d9b55c6811
5 changed files with 103 additions and 327 deletions
@@ -167,7 +167,7 @@ class NavButtonSettingsStore(context: Context) {
} }
fun sanitizeDuration(durationMs: Int): Int { fun sanitizeDuration(durationMs: Int): Int {
return durationMs.coerceIn(MIN_LONG_PRESS_DURATION_MS, MAX_LONG_PRESS_DURATION_MS) return durationMs.coerceIn(MIN_DURATION_MS, MAX_DURATION_MS)
} }
fun sanitizeSideArrowRepeatSpeed(stepsPerSecond: Float): Float { fun sanitizeSideArrowRepeatSpeed(stepsPerSecond: Float): Float {
@@ -222,8 +222,6 @@ class NavButtonSettingsStore(context: Context) {
const val KEY_SIDE_ARROW_LONG_PRESS_DURATION_MS = "side_arrow_long_press_duration_ms" const val KEY_SIDE_ARROW_LONG_PRESS_DURATION_MS = "side_arrow_long_press_duration_ms"
private const val KEY_LAST_UPDATED_AT_MS = "last_updated_at_ms" private const val KEY_LAST_UPDATED_AT_MS = "last_updated_at_ms"
const val MIN_LONG_PRESS_DURATION_MS = 100
const val MAX_LONG_PRESS_DURATION_MS = 10_000
const val MIN_DURATION_MS = 100 const val MIN_DURATION_MS = 100
const val MAX_DURATION_MS = 10_000 const val MAX_DURATION_MS = 10_000
const val DURATION_STEP_MS = 100 const val DURATION_STEP_MS = 100
@@ -370,7 +368,7 @@ class NavButtonSettingsStore(context: Context) {
} }
private fun sanitizeDuration(durationMs: Int): Int { private fun sanitizeDuration(durationMs: Int): Int {
return durationMs.coerceIn(MIN_LONG_PRESS_DURATION_MS, MAX_LONG_PRESS_DURATION_MS) return durationMs.coerceIn(MIN_DURATION_MS, MAX_DURATION_MS)
} }
} }
} }
@@ -24,7 +24,6 @@ import android.hardware.camera2.CameraCharacteristics
import android.hardware.camera2.CameraManager import android.hardware.camera2.CameraManager
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
import android.os.Process
import android.os.SystemClock import android.os.SystemClock
import android.provider.Settings import android.provider.Settings
import android.util.Log import android.util.Log
@@ -101,7 +100,6 @@ class NavButtons : XposedModule() {
} }
initContextAndHandler() initContextAndHandler()
systemServerHookInstalled = hookSystemServerHomeLongPress(param.classLoader) systemServerHookInstalled = hookSystemServerHomeLongPress(param.classLoader)
trace("System server hooks installed=$systemServerHookInstalled")
} }
private fun handleTargetPackage(packageName: String, classLoader: ClassLoader?) { private fun handleTargetPackage(packageName: String, classLoader: ClassLoader?) {
@@ -111,7 +109,6 @@ class NavButtons : XposedModule() {
} }
initContextAndHandler() initContextAndHandler()
systemUiHookInstalled = hookSystemUiNavigationButtons(classLoader) systemUiHookInstalled = hookSystemUiNavigationButtons(classLoader)
trace("SystemUI hooks installed=$systemUiHookInstalled")
return return
} }
@@ -121,7 +118,6 @@ class NavButtons : XposedModule() {
} }
initContextAndHandler() initContextAndHandler()
launcherHookInstalled = hookHoneyspaceTaskbar(classLoader) launcherHookInstalled = hookHoneyspaceTaskbar(classLoader)
trace("Honeyspace hooks installed=$launcherHookInstalled")
return return
} }
@@ -221,13 +217,6 @@ class NavButtons : XposedModule() {
systemUiLongPressTriggered[keyButtonView] = false systemUiLongPressTriggered[keyButtonView] = false
cancelSystemUiHomeStockLongPressGuard(keyButtonView) cancelSystemUiHomeStockLongPressGuard(keyButtonView)
systemUiHomeStockPressCanceled.remove(keyButtonView) systemUiHomeStockPressCanceled.remove(keyButtonView)
if (buttonId == NavButtonId.HOME) {
val config = getButtonConfig(buttonId)
traceHome(
"KeyButtonView.onTouchEvent DOWN",
"press=${config.pressAction.storageValue} long=${config.longPressAction.storageValue} duration=${config.longPressDurationMs}",
)
}
val result = chain.proceed() val result = chain.proceed()
rescheduleSystemUiLongPress(keyButtonView, buttonId) rescheduleSystemUiLongPress(keyButtonView, buttonId)
scheduleSystemUiHomeStockLongPressGuard(keyButtonView, buttonId) scheduleSystemUiHomeStockLongPressGuard(keyButtonView, buttonId)
@@ -236,9 +225,6 @@ class NavButtons : XposedModule() {
MotionEvent.ACTION_UP -> { MotionEvent.ACTION_UP -> {
if (systemUiLongPressTriggered[keyButtonView] == true) { if (systemUiLongPressTriggered[keyButtonView] == true) {
if (buttonId == NavButtonId.HOME) {
traceHome("KeyButtonView.onTouchEvent UP", "converted to CANCEL after long press")
}
return@intercept proceedWithCanceledAction(motionEvent) { return@intercept proceedWithCanceledAction(motionEvent) {
chain.proceed() chain.proceed()
}.also { }.also {
@@ -269,21 +255,12 @@ class NavButtons : XposedModule() {
updateContextFromView(keyButtonView) updateContextFromView(keyButtonView)
performConfiguredAction(pressAction) performConfiguredAction(pressAction)
} }
if (buttonId == NavButtonId.HOME) {
traceHome(
"KeyButtonView.onTouchEvent UP",
"override=$shouldOverridePress ${systemUiHomeState(keyButtonView)}",
)
}
cancelSystemUiHomeStockLongPressGuard(keyButtonView) cancelSystemUiHomeStockLongPressGuard(keyButtonView)
systemUiHomeStockPressCanceled.remove(keyButtonView) systemUiHomeStockPressCanceled.remove(keyButtonView)
result result
} }
MotionEvent.ACTION_CANCEL -> { MotionEvent.ACTION_CANCEL -> {
if (buttonId == NavButtonId.HOME) {
traceHome("KeyButtonView.onTouchEvent CANCEL", "clearing long-press state")
}
cancelSystemUiHomeStockLongPressGuard(keyButtonView) cancelSystemUiHomeStockLongPressGuard(keyButtonView)
systemUiLongPressTriggered.remove(keyButtonView) systemUiLongPressTriggered.remove(keyButtonView)
systemUiHomeStockPressCanceled.remove(keyButtonView) systemUiHomeStockPressCanceled.remove(keyButtonView)
@@ -307,9 +284,6 @@ class NavButtons : XposedModule() {
return@intercept chain.proceed() return@intercept chain.proceed()
} }
if (buttonId == NavButtonId.HOME) {
traceHome("KeyButtonView\$1.run", "long=${longPressAction.storageValue}")
}
updateContextFromView(keyButtonView) updateContextFromView(keyButtonView)
systemUiLongPressTriggered[keyButtonView] = true systemUiLongPressTriggered[keyButtonView] = true
cancelSystemUiKeyPress(keyButtonView) cancelSystemUiKeyPress(keyButtonView)
@@ -340,11 +314,6 @@ class NavButtons : XposedModule() {
} }
if (action == KeyEvent.ACTION_DOWN && sendEventFlags(chain.args).hasFlag(KeyEvent.FLAG_LONG_PRESS)) { if (action == KeyEvent.ACTION_DOWN && sendEventFlags(chain.args).hasFlag(KeyEvent.FLAG_LONG_PRESS)) {
traceHome(
"KeyButtonView.sendEvent",
"suppressed stock long-press action=${keyActionName(action)} " +
"args=${sendEventArgsToTraceString(chain.args)} ${systemUiHomeState(keyButtonView)}",
)
return@intercept null return@intercept null
} }
@@ -385,7 +354,6 @@ class NavButtons : XposedModule() {
deoptimizeMethodIfPresent(longPressOnHomeWithEvent) deoptimizeMethodIfPresent(longPressOnHomeWithEvent)
hook(longPressOnHomeWithEvent).intercept { chain -> hook(longPressOnHomeWithEvent).intercept { chain ->
val longPressAction = getButtonConfig(NavButtonId.HOME).longPressAction val longPressAction = getButtonConfig(NavButtonId.HOME).longPressAction
traceHome("PhoneWindowManager.handleLongPressOnHome(KeyEvent)", "long=${longPressAction.storageValue}")
if (longPressAction == NavButtonAction.STOCK) { if (longPressAction == NavButtonAction.STOCK) {
return@intercept chain.proceed() return@intercept chain.proceed()
} }
@@ -400,7 +368,6 @@ class NavButtons : XposedModule() {
deoptimizeMethodIfPresent(longPressOnHomeLegacy) deoptimizeMethodIfPresent(longPressOnHomeLegacy)
hook(longPressOnHomeLegacy).intercept { chain -> hook(longPressOnHomeLegacy).intercept { chain ->
val longPressAction = getButtonConfig(NavButtonId.HOME).longPressAction val longPressAction = getButtonConfig(NavButtonId.HOME).longPressAction
traceHome("PhoneWindowManager.handleLongPressOnHome(int,long)", "long=${longPressAction.storageValue}")
if (longPressAction == NavButtonAction.STOCK) { if (longPressAction == NavButtonAction.STOCK) {
return@intercept chain.proceed() return@intercept chain.proceed()
} }
@@ -415,7 +382,6 @@ class NavButtons : XposedModule() {
deoptimizeMethodIfPresent(launchAssistActionMethod) deoptimizeMethodIfPresent(launchAssistActionMethod)
hook(launchAssistActionMethod).intercept { chain -> hook(launchAssistActionMethod).intercept { chain ->
val invocationType = chain.args[3] as? Int ?: ASSIST_INVOCATION_TYPE_UNKNOWN val invocationType = chain.args[3] as? Int ?: ASSIST_INVOCATION_TYPE_UNKNOWN
traceHome("PhoneWindowManager.launchAssistAction", "invocationType=$invocationType")
if (invocationType != ASSIST_INVOCATION_TYPE_HOME_BUTTON_LONG_PRESS) { if (invocationType != ASSIST_INVOCATION_TYPE_HOME_BUTTON_LONG_PRESS) {
return@intercept chain.proceed() return@intercept chain.proceed()
} }
@@ -425,7 +391,6 @@ class NavButtons : XposedModule() {
return@intercept chain.proceed() return@intercept chain.proceed()
} }
traceHome("PhoneWindowManager.launchAssistAction", "blocked long=${longPressAction.storageValue}")
updateContextFromField(chain.thisObject, "mContext") updateContextFromField(chain.thisObject, "mContext")
performHomeLongPressAction(longPressAction) performHomeLongPressAction(longPressAction)
null null
@@ -503,13 +468,6 @@ class NavButtons : XposedModule() {
honeyspaceLongPressTriggered[navButtonView] = false honeyspaceLongPressTriggered[navButtonView] = false
cancelHoneyspaceHomeStockLongPressGuard(navButtonView) cancelHoneyspaceHomeStockLongPressGuard(navButtonView)
honeyspaceHomeStockPressCanceled.remove(navButtonView) honeyspaceHomeStockPressCanceled.remove(navButtonView)
if (buttonId == NavButtonId.HOME) {
val config = getButtonConfig(buttonId)
traceHome(
"Honeyspace.onTouchEvent DOWN",
"press=${config.pressAction.storageValue} long=${config.longPressAction.storageValue} duration=${config.longPressDurationMs}",
)
}
val result = chain.proceed() val result = chain.proceed()
rescheduleHoneyspaceLongPress(navButtonView, runnableClass, buttonId) rescheduleHoneyspaceLongPress(navButtonView, runnableClass, buttonId)
scheduleHoneyspaceHomeStockLongPressGuard(navButtonView, buttonId) scheduleHoneyspaceHomeStockLongPressGuard(navButtonView, buttonId)
@@ -519,9 +477,6 @@ class NavButtons : XposedModule() {
MotionEvent.ACTION_UP -> { MotionEvent.ACTION_UP -> {
val longPressTriggered = honeyspaceLongPressTriggered[navButtonView] == true val longPressTriggered = honeyspaceLongPressTriggered[navButtonView] == true
if (longPressTriggered) { if (longPressTriggered) {
if (buttonId == NavButtonId.HOME) {
traceHome("Honeyspace.onTouchEvent UP", "converted to CANCEL after long press")
}
return@intercept proceedWithCanceledAction(motionEvent) { return@intercept proceedWithCanceledAction(motionEvent) {
chain.proceed() chain.proceed()
}.also { }.also {
@@ -554,19 +509,10 @@ class NavButtons : XposedModule() {
cancelHoneyspaceHomeStockLongPressGuard(navButtonView) cancelHoneyspaceHomeStockLongPressGuard(navButtonView)
honeyspaceLongPressTriggered.remove(navButtonView) honeyspaceLongPressTriggered.remove(navButtonView)
honeyspaceHomeStockPressCanceled.remove(navButtonView) honeyspaceHomeStockPressCanceled.remove(navButtonView)
if (buttonId == NavButtonId.HOME) {
traceHome(
"Honeyspace.onTouchEvent UP",
"override=$shouldOverridePress ${honeyspaceHomeState(navButtonView)}",
)
}
result result
} }
MotionEvent.ACTION_CANCEL -> { MotionEvent.ACTION_CANCEL -> {
if (buttonId == NavButtonId.HOME) {
traceHome("Honeyspace.onTouchEvent CANCEL", "clearing long-press state")
}
cancelHoneyspaceHomeStockLongPressGuard(navButtonView) cancelHoneyspaceHomeStockLongPressGuard(navButtonView)
honeyspaceLongPressTriggered.remove(navButtonView) honeyspaceLongPressTriggered.remove(navButtonView)
honeyspaceHomeStockPressCanceled.remove(navButtonView) honeyspaceHomeStockPressCanceled.remove(navButtonView)
@@ -601,9 +547,6 @@ class NavButtons : XposedModule() {
return@intercept chain.proceed() return@intercept chain.proceed()
} }
if (buttonId == NavButtonId.HOME) {
traceHome("Honeyspace runnable", "long=${longPressAction.storageValue}")
}
updateContextFromView(navButtonView) updateContextFromView(navButtonView)
markHoneyspaceLongClicked(navButtonView) markHoneyspaceLongClicked(navButtonView)
cancelHoneyspaceHomeStockLongPressGuard(navButtonView) cancelHoneyspaceHomeStockLongPressGuard(navButtonView)
@@ -712,18 +655,6 @@ class NavButtons : XposedModule() {
} }
} }
private fun findHoneyspaceNavContainer(view: View): android.view.ViewGroup? {
var current = view.parent as? View
repeat(HONEYSPACE_NAV_CONTAINER_PARENT_DEPTH) {
val target = current ?: return null
if (isHoneyspaceNavButtonContainer(target)) {
return target as? android.view.ViewGroup
}
current = target.parent as? View
}
return null
}
private fun refreshHoneyspaceSideArrowLayout(container: android.view.ViewGroup, reason: String) { private fun refreshHoneyspaceSideArrowLayout(container: android.view.ViewGroup, reason: String) {
try { try {
applyNativeHoneyspaceSideArrows(container, reason) applyNativeHoneyspaceSideArrows(container, reason)
@@ -1491,14 +1422,9 @@ class NavButtons : XposedModule() {
} }
private fun configureFoldedSideArrowButtons(navBarView: Any) { private fun configureFoldedSideArrowButtons(navBarView: Any) {
if (!isSideArrowsEnabled()) { if (isSideArrowsEnabled()) {
return configureSideArrowDispatcherButtons(navBarView, navBarView)
} }
if (!configureSideArrowDispatcherButtons(navBarView, navBarView)) {
return
}
} }
private fun configureSideArrowDispatcherButtons( private fun configureSideArrowDispatcherButtons(
@@ -1880,27 +1806,6 @@ class NavButtons : XposedModule() {
} }
} }
private fun trace(message: String) {
if (!DEBUG_TRACE) {
return
}
val fullMessage =
"[proc=${currentProcessLabel()} pid=${Process.myPid()} uptime=${SystemClock.uptimeMillis()}] $message"
Log.i(TAG, fullMessage)
log(fullMessage)
}
private fun traceHome(source: String, details: String) {
trace("HOME $source :: $details")
}
private fun currentProcessLabel(): String {
return runCatching {
callStaticMethod(findClass("android.app.ActivityThread", null), "currentProcessName")
?.toString()
}.getOrNull() ?: context?.packageName ?: "unknown"
}
private fun log(message: String) { private fun log(message: String) {
log(Log.INFO, TAG, message) log(Log.INFO, TAG, message)
} }
@@ -1945,11 +1850,9 @@ class NavButtons : XposedModule() {
private fun performHomeLongPressAction(action: NavButtonAction) { private fun performHomeLongPressAction(action: NavButtonAction) {
if (wasHomeLongPressHandledRecently()) { if (wasHomeLongPressHandledRecently()) {
traceHome("performHomeLongPressAction", "deduped action=${action.storageValue}")
return return
} }
noteHomeLongPressHandled() noteHomeLongPressHandled()
traceHome("performHomeLongPressAction", "executing action=${action.storageValue}")
performConfiguredAction(action) performConfiguredAction(action)
} }
@@ -1957,46 +1860,52 @@ class NavButtons : XposedModule() {
if (buttonIdForKeyCode(getIntField(keyButtonView, "mCode")) == NavButtonId.HOME && if (buttonIdForKeyCode(getIntField(keyButtonView, "mCode")) == NavButtonId.HOME &&
systemUiHomeStockPressCanceled[keyButtonView] == true systemUiHomeStockPressCanceled[keyButtonView] == true
) { ) {
traceHome("cancelSystemUiKeyPress", "stock key was already canceled by guard")
abortSystemUiKeyGesture(keyButtonView) abortSystemUiKeyGesture(keyButtonView)
return return
} }
traceHome("cancelSystemUiKeyPress", "sending canceled key-up")
abortSystemUiKeyGesture(keyButtonView) abortSystemUiKeyGesture(keyButtonView)
sendSystemUiCanceledKeyUp(keyButtonView) sendSystemUiCanceledKeyUp(keyButtonView)
} }
private fun scheduleSystemUiHomeStockLongPressGuard(keyButtonView: Any, buttonId: NavButtonId) { private fun scheduleSystemUiHomeStockLongPressGuard(keyButtonView: Any, buttonId: NavButtonId) {
if (buttonId != NavButtonId.HOME) { scheduleHomeStockLongPressGuard(
return keyButtonView,
} buttonId,
if (getButtonConfig(buttonId).longPressAction == NavButtonAction.STOCK) { systemUiHomeStockLongPressGuards,
return systemUiLongPressTriggered,
} systemUiHomeStockPressCanceled,
::sendSystemUiCanceledKeyUp,
val view = keyButtonView as? View ?: return )
val delayMs = (ViewConfiguration.getLongPressTimeout() - STOCK_LONG_PRESS_GUARD_EARLY_MS)
.coerceAtLeast(STOCK_LONG_PRESS_GUARD_MIN_DELAY_MS)
val guard = Runnable {
if (!view.isPressed || systemUiLongPressTriggered[keyButtonView] == true) {
return@Runnable
}
traceHome("stock long-press guard", "canceling original Home key after ${delayMs}ms")
systemUiHomeStockPressCanceled[keyButtonView] = true
sendSystemUiCanceledKeyUp(keyButtonView)
}
systemUiHomeStockLongPressGuards[keyButtonView] = guard
view.postDelayed(guard, delayMs.toLong())
} }
private fun cancelSystemUiHomeStockLongPressGuard(keyButtonView: Any) { private fun cancelSystemUiHomeStockLongPressGuard(keyButtonView: Any) {
val guard = systemUiHomeStockLongPressGuards.remove(keyButtonView) ?: return cancelHomeStockLongPressGuard(keyButtonView, systemUiHomeStockLongPressGuards)
(keyButtonView as? View)?.removeCallbacks(guard)
} }
private fun scheduleHoneyspaceHomeStockLongPressGuard(navButtonView: Any, buttonId: NavButtonId) { private fun scheduleHoneyspaceHomeStockLongPressGuard(navButtonView: Any, buttonId: NavButtonId) {
scheduleHomeStockLongPressGuard(
navButtonView,
buttonId,
honeyspaceHomeStockLongPressGuards,
honeyspaceLongPressTriggered,
honeyspaceHomeStockPressCanceled,
::sendHoneyspaceCanceledKeyUp,
)
}
private fun cancelHoneyspaceHomeStockLongPressGuard(navButtonView: Any) {
cancelHomeStockLongPressGuard(navButtonView, honeyspaceHomeStockLongPressGuards)
}
private fun scheduleHomeStockLongPressGuard(
target: Any,
buttonId: NavButtonId,
guards: WeakHashMap<Any, Runnable>,
longPressTriggered: WeakHashMap<Any, Boolean>,
stockPressCanceled: WeakHashMap<Any, Boolean>,
sendCanceledKeyUp: (Any) -> Unit,
) {
if (buttonId != NavButtonId.HOME) { if (buttonId != NavButtonId.HOME) {
return return
} }
@@ -2004,25 +1913,24 @@ class NavButtons : XposedModule() {
return return
} }
val view = navButtonView as? View ?: return val view = target as? View ?: return
val delayMs = (ViewConfiguration.getLongPressTimeout() - STOCK_LONG_PRESS_GUARD_EARLY_MS) val delayMs = (ViewConfiguration.getLongPressTimeout() - STOCK_LONG_PRESS_GUARD_EARLY_MS)
.coerceAtLeast(STOCK_LONG_PRESS_GUARD_MIN_DELAY_MS) .coerceAtLeast(STOCK_LONG_PRESS_GUARD_MIN_DELAY_MS)
val guard = Runnable { val guard = Runnable {
if (!view.isPressed || honeyspaceLongPressTriggered[navButtonView] == true) { if (!view.isPressed || longPressTriggered[target] == true) {
return@Runnable return@Runnable
} }
traceHome("Honeyspace stock long-press guard", "canceling original Home key after ${delayMs}ms") stockPressCanceled[target] = true
honeyspaceHomeStockPressCanceled[navButtonView] = true sendCanceledKeyUp(target)
sendHoneyspaceCanceledKeyUp(navButtonView)
} }
honeyspaceHomeStockLongPressGuards[navButtonView] = guard guards[target] = guard
view.postDelayed(guard, delayMs.toLong()) view.postDelayed(guard, delayMs.toLong())
} }
private fun cancelHoneyspaceHomeStockLongPressGuard(navButtonView: Any) { private fun cancelHomeStockLongPressGuard(target: Any, guards: WeakHashMap<Any, Runnable>) {
val guard = honeyspaceHomeStockLongPressGuards.remove(navButtonView) ?: return val guard = guards.remove(target) ?: return
(navButtonView as? View)?.removeCallbacks(guard) (target as? View)?.removeCallbacks(guard)
} }
private fun abortSystemUiKeyGesture(keyButtonView: Any) { private fun abortSystemUiKeyGesture(keyButtonView: Any) {
@@ -2087,7 +1995,6 @@ class NavButtons : XposedModule() {
} }
private fun dispatchSystemUiHomeTap(keyButtonView: Any) { private fun dispatchSystemUiHomeTap(keyButtonView: Any) {
traceHome("dispatchSystemUiHomeTap", "sending stock tap after guard cancel")
try { try {
callMethod( callMethod(
keyButtonView, keyButtonView,
@@ -2109,7 +2016,6 @@ class NavButtons : XposedModule() {
} }
private fun dispatchHoneyspaceHomeTap(navButtonView: Any) { private fun dispatchHoneyspaceHomeTap(navButtonView: Any) {
traceHome("dispatchHoneyspaceHomeTap", "sending stock tap after guard cancel")
if (callIntIntMethodIfExists(navButtonView, listOf("sendEvent", "sendKeyEvent"), KeyEvent.ACTION_DOWN, 0) && if (callIntIntMethodIfExists(navButtonView, listOf("sendEvent", "sendKeyEvent"), KeyEvent.ACTION_DOWN, 0) &&
callIntIntMethodIfExists(navButtonView, listOf("sendEvent", "sendKeyEvent"), KeyEvent.ACTION_UP, 0) callIntIntMethodIfExists(navButtonView, listOf("sendEvent", "sendKeyEvent"), KeyEvent.ACTION_UP, 0)
) { ) {
@@ -2220,32 +2126,6 @@ class NavButtons : XposedModule() {
return methodsBySignature.values.toList() return methodsBySignature.values.toList()
} }
private fun systemUiHomeState(keyButtonView: Any): String {
return "pressed=${(keyButtonView as? View)?.isPressed == true} " +
"longClicked=${getFieldValue(keyButtonView, "mLongClicked") == true} " +
"triggered=${systemUiLongPressTriggered[keyButtonView] == true} " +
"stockCanceled=${systemUiHomeStockPressCanceled[keyButtonView] == true}"
}
private fun honeyspaceHomeState(navButtonView: Any): String {
return "pressed=${(navButtonView as? View)?.isPressed == true} " +
"triggered=${honeyspaceLongPressTriggered[navButtonView] == true} " +
"stockCanceled=${honeyspaceHomeStockPressCanceled[navButtonView] == true}"
}
private fun sendEventArgsToTraceString(args: Any?): String {
val values = argsToList(args)
return values.mapIndexed { index, arg ->
if (index == 0 && arg is Int) {
keyActionName(arg)
} else if (index == 1 && arg is Int) {
"flags=0x${arg.toString(16)}"
} else {
traceValue(arg)
}
}.joinToString(prefix = "[", postfix = "]")
}
private fun sendEventFlags(args: Any?): Int { private fun sendEventFlags(args: Any?): Int {
return argsToList(args).getOrNull(1) as? Int ?: 0 return argsToList(args).getOrNull(1) as? Int ?: 0
} }
@@ -2259,29 +2139,6 @@ class NavButtons : XposedModule() {
} }
} }
private fun traceValue(value: Any?): String {
return when (value) {
is Long,
is Float,
is Double,
is Boolean,
is String,
is Int,
null,
-> value.toString()
else -> value.javaClass.simpleName
}
}
private fun keyActionName(action: Int): String {
return when (action) {
KeyEvent.ACTION_DOWN -> "DOWN"
KeyEvent.ACTION_UP -> "UP"
else -> action.toString()
}
}
private fun Int.hasFlag(flag: Int): Boolean { private fun Int.hasFlag(flag: Int): Boolean {
return this and flag == flag return this and flag == flag
} }
@@ -2450,7 +2307,6 @@ class NavButtons : XposedModule() {
} }
private companion object { private companion object {
const val DEBUG_TRACE = false
const val TAG = "NavButtons" const val TAG = "NavButtons"
const val ASSIST_INVOCATION_TYPE_UNKNOWN = 0 const val ASSIST_INVOCATION_TYPE_UNKNOWN = 0
const val ASSIST_INVOCATION_TYPE_HOME_BUTTON_LONG_PRESS = 5 const val ASSIST_INVOCATION_TYPE_HOME_BUTTON_LONG_PRESS = 5
@@ -22,7 +22,6 @@ import android.widget.TextView
import android.widget.Toast import android.widget.Toast
import java.text.DecimalFormatSymbols import java.text.DecimalFormatSymbols
import java.util.Locale import java.util.Locale
import java.util.concurrent.TimeUnit
class SettingsActivity : Activity() { class SettingsActivity : Activity() {
private val handler = Handler(Looper.getMainLooper()) private val handler = Handler(Looper.getMainLooper())
@@ -154,6 +153,52 @@ class SettingsActivity : Activity() {
} }
} }
private fun attachTestButton(button: Button, durationProvider: () -> Int) {
button.setOnTouchListener { view, event ->
when (event.actionMasked) {
MotionEvent.ACTION_DOWN -> {
view.isPressed = true
startTestPreview(durationProvider())
true
}
MotionEvent.ACTION_UP,
MotionEvent.ACTION_CANCEL,
-> {
view.isPressed = false
stopTestPreview()
true
}
else -> false
}
}
}
private fun <T> bindSpinner(
spinner: Spinner,
items: List<T>,
selectedItem: T,
labelRes: (T) -> Int,
onSelected: (T) -> Unit,
) {
val adapter = ArrayAdapter(
this,
R.layout.item_spinner_selected,
items.map { getString(labelRes(it)) },
)
adapter.setDropDownViewResource(R.layout.item_spinner_dropdown)
spinner.adapter = adapter
spinner.setSelection(items.indexOf(selectedItem).coerceAtLeast(0), false)
spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
onSelected(items[position])
}
override fun onNothingSelected(parent: AdapterView<*>?) = Unit
}
}
private inner class NavButtonSectionController( private inner class NavButtonSectionController(
sectionView: View, sectionView: View,
private val buttonId: NavButtonId, private val buttonId: NavButtonId,
@@ -188,7 +233,7 @@ class SettingsActivity : Activity() {
applyDuration(config.longPressDurationMs, persist = false) applyDuration(config.longPressDurationMs, persist = false)
bindDurationInput() bindDurationInput()
bindStepButtons() bindStepButtons()
bindTestButton() attachTestButton(testButton, ::resolveDurationForUse)
} }
private fun bindActionSpinner( private fun bindActionSpinner(
@@ -196,27 +241,12 @@ class SettingsActivity : Activity() {
selectedAction: NavButtonAction, selectedAction: NavButtonAction,
storeAction: (NavButtonId, NavButtonAction) -> Unit, storeAction: (NavButtonId, NavButtonAction) -> Unit,
) { ) {
val labels = NavButtonAction.entries.map { getString(it.labelRes) } bindSpinner(
val adapter = ArrayAdapter( spinner,
this@SettingsActivity, NavButtonAction.entries,
R.layout.item_spinner_selected, selectedAction,
labels, NavButtonAction::labelRes,
) ) { action -> storeAction(buttonId, action) }
adapter.setDropDownViewResource(R.layout.item_spinner_dropdown)
spinner.adapter = adapter
spinner.setSelection(NavButtonAction.entries.indexOf(selectedAction), false)
spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(
parent: AdapterView<*>?,
view: View?,
position: Int,
id: Long,
) {
storeAction(buttonId, NavButtonAction.entries[position])
}
override fun onNothingSelected(parent: AdapterView<*>?) = Unit
}
} }
private fun bindDurationInput() { private fun bindDurationInput() {
@@ -264,28 +294,6 @@ class SettingsActivity : Activity() {
} }
} }
private fun bindTestButton() {
testButton.setOnTouchListener { view, event ->
when (event.actionMasked) {
MotionEvent.ACTION_DOWN -> {
view.isPressed = true
startTestPreview(resolveDurationForUse())
true
}
MotionEvent.ACTION_UP,
MotionEvent.ACTION_CANCEL,
-> {
view.isPressed = false
stopTestPreview()
true
}
else -> false
}
}
}
private fun adjustDuration(deltaMs: Int) { private fun adjustDuration(deltaMs: Int) {
val current = resolveDurationForUse() val current = resolveDurationForUse()
val updated = (current + deltaMs).coerceIn( val updated = (current + deltaMs).coerceIn(
@@ -344,8 +352,6 @@ class SettingsActivity : Activity() {
private val durationPlusButton: Button = private val durationPlusButton: Button =
sectionView.findViewById(R.id.side_arrow_duration_plus_button) sectionView.findViewById(R.id.side_arrow_duration_plus_button)
private val testButton: Button = sectionView.findViewById(R.id.side_arrow_test_button) private val testButton: Button = sectionView.findViewById(R.id.side_arrow_test_button)
private val restartSamsungUiButton: Button =
sectionView.findViewById(R.id.restart_samsung_ui_button)
private val decimalSeparator = DecimalFormatSymbols.getInstance().decimalSeparator private val decimalSeparator = DecimalFormatSymbols.getInstance().decimalSeparator
private var lastValidDurationMs = settingsStore.defaultLongPressDurationMs() private var lastValidDurationMs = settingsStore.defaultLongPressDurationMs()
@@ -362,7 +368,7 @@ class SettingsActivity : Activity() {
applyDuration(settingsStore.getSideArrowLongPressDurationMs(), persist = false) applyDuration(settingsStore.getSideArrowLongPressDurationMs(), persist = false)
bindDurationInput() bindDurationInput()
bindDurationButtons() bindDurationButtons()
bindTestButton() attachTestButton(testButton, ::resolveDurationForUse)
updateOptionsEnabled() updateOptionsEnabled()
sideArrowsCheckbox.setOnCheckedChangeListener { _, isChecked -> sideArrowsCheckbox.setOnCheckedChangeListener { _, isChecked ->
@@ -375,50 +381,18 @@ class SettingsActivity : Activity() {
), ),
) )
} }
restartSamsungUiButton.setOnClickListener {
restartSamsungUiButton.isEnabled = false
Toast.makeText(
this@SettingsActivity,
"Restarting One UI Home and SystemUI...",
Toast.LENGTH_SHORT,
).show()
Thread {
val result = restartSamsungUiProcesses()
handler.post {
restartSamsungUiButton.isEnabled = true
Toast.makeText(this@SettingsActivity, result, Toast.LENGTH_LONG).show()
}
}.start()
}
} }
private fun bindLongPressActionSpinner() { private fun bindLongPressActionSpinner() {
val labels = SideArrowLongPressAction.entries.map { getString(it.labelRes) } bindSpinner(
val adapter = ArrayAdapter( longPressActionSpinner,
this@SettingsActivity, SideArrowLongPressAction.entries,
R.layout.item_spinner_selected, settingsStore.getSideArrowLongPressAction(),
labels, SideArrowLongPressAction::labelRes,
) ) { action ->
adapter.setDropDownViewResource(R.layout.item_spinner_dropdown)
longPressActionSpinner.adapter = adapter
longPressActionSpinner.setSelection(
SideArrowLongPressAction.entries.indexOf(settingsStore.getSideArrowLongPressAction()),
false,
)
longPressActionSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(
parent: AdapterView<*>?,
view: View?,
position: Int,
id: Long,
) {
val action = SideArrowLongPressAction.entries[position]
settingsStore.setSideArrowLongPressAction(action) settingsStore.setSideArrowLongPressAction(action)
updateRepeatSpeedVisibility(action) updateRepeatSpeedVisibility(action)
} }
override fun onNothingSelected(parent: AdapterView<*>?) = Unit
}
updateRepeatSpeedVisibility(settingsStore.getSideArrowLongPressAction()) updateRepeatSpeedVisibility(settingsStore.getSideArrowLongPressAction())
} }
@@ -514,28 +488,6 @@ class SettingsActivity : Activity() {
} }
} }
private fun bindTestButton() {
testButton.setOnTouchListener { view, event ->
when (event.actionMasked) {
MotionEvent.ACTION_DOWN -> {
view.isPressed = true
startTestPreview(resolveDurationForUse())
true
}
MotionEvent.ACTION_UP,
MotionEvent.ACTION_CANCEL,
-> {
view.isPressed = false
stopTestPreview()
true
}
else -> false
}
}
}
private fun updateOptionsEnabled() { private fun updateOptionsEnabled() {
val enabled = sideArrowsCheckbox.isChecked val enabled = sideArrowsCheckbox.isChecked
optionsContainer.alpha = if (enabled) 1f else 0.45f optionsContainer.alpha = if (enabled) 1f else 0.45f
@@ -641,27 +593,5 @@ class SettingsActivity : Activity() {
} }
} }
private fun restartSamsungUiProcesses(): String {
return try {
val command = listOf(
"am force-stop com.sec.android.app.launcher",
"killall com.android.systemui",
"sleep 1",
"am start -a android.intent.action.MAIN -c android.intent.category.HOME",
).joinToString("; ")
val process = Runtime.getRuntime().exec(arrayOf("su", "-c", command))
val finished = process.waitFor(10, TimeUnit.SECONDS)
if (!finished) {
process.destroyForcibly()
"Restart command timed out."
} else if (process.exitValue() == 0) {
"Restart command completed."
} else {
"Restart command failed. Is root allowed?"
}
} catch (_: Throwable) {
"Restart command failed. Is root allowed?"
}
}
} }
} }
@@ -176,11 +176,4 @@
</LinearLayout> </LinearLayout>
<Button
android:id="@+id/restart_samsung_ui_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="14dp"
android:text="@string/restart_samsung_ui_button_label" />
</LinearLayout> </LinearLayout>
-1
View File
@@ -11,7 +11,6 @@
<string name="side_arrow_long_press_single_step">Single step</string> <string name="side_arrow_long_press_single_step">Single step</string>
<string name="side_arrow_long_press_multiple_steps">Multiple steps</string> <string name="side_arrow_long_press_multiple_steps">Multiple steps</string>
<string name="side_arrow_repeat_speed_label">Repeat speed (steps/sec)</string> <string name="side_arrow_repeat_speed_label">Repeat speed (steps/sec)</string>
<string name="restart_samsung_ui_button_label">Restart One UI Home + SystemUI</string>
<string name="press_action_label">When pressed</string> <string name="press_action_label">When pressed</string>
<string name="long_press_action_label">When long-pressed</string> <string name="long_press_action_label">When long-pressed</string>
<string name="long_press_duration_label">Long-press duration (ms)</string> <string name="long_press_duration_label">Long-press duration (ms)</string>