Clean up navigation module code
This commit is contained in:
@@ -167,7 +167,7 @@ class NavButtonSettingsStore(context: Context) {
|
||||
}
|
||||
|
||||
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 {
|
||||
@@ -222,8 +222,6 @@ class NavButtonSettingsStore(context: Context) {
|
||||
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"
|
||||
|
||||
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 MAX_DURATION_MS = 10_000
|
||||
const val DURATION_STEP_MS = 100
|
||||
@@ -370,7 +368,7 @@ class NavButtonSettingsStore(context: Context) {
|
||||
}
|
||||
|
||||
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.os.Handler
|
||||
import android.os.Looper
|
||||
import android.os.Process
|
||||
import android.os.SystemClock
|
||||
import android.provider.Settings
|
||||
import android.util.Log
|
||||
@@ -101,7 +100,6 @@ class NavButtons : XposedModule() {
|
||||
}
|
||||
initContextAndHandler()
|
||||
systemServerHookInstalled = hookSystemServerHomeLongPress(param.classLoader)
|
||||
trace("System server hooks installed=$systemServerHookInstalled")
|
||||
}
|
||||
|
||||
private fun handleTargetPackage(packageName: String, classLoader: ClassLoader?) {
|
||||
@@ -111,7 +109,6 @@ class NavButtons : XposedModule() {
|
||||
}
|
||||
initContextAndHandler()
|
||||
systemUiHookInstalled = hookSystemUiNavigationButtons(classLoader)
|
||||
trace("SystemUI hooks installed=$systemUiHookInstalled")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -121,7 +118,6 @@ class NavButtons : XposedModule() {
|
||||
}
|
||||
initContextAndHandler()
|
||||
launcherHookInstalled = hookHoneyspaceTaskbar(classLoader)
|
||||
trace("Honeyspace hooks installed=$launcherHookInstalled")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -221,13 +217,6 @@ class NavButtons : XposedModule() {
|
||||
systemUiLongPressTriggered[keyButtonView] = false
|
||||
cancelSystemUiHomeStockLongPressGuard(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()
|
||||
rescheduleSystemUiLongPress(keyButtonView, buttonId)
|
||||
scheduleSystemUiHomeStockLongPressGuard(keyButtonView, buttonId)
|
||||
@@ -236,9 +225,6 @@ class NavButtons : XposedModule() {
|
||||
|
||||
MotionEvent.ACTION_UP -> {
|
||||
if (systemUiLongPressTriggered[keyButtonView] == true) {
|
||||
if (buttonId == NavButtonId.HOME) {
|
||||
traceHome("KeyButtonView.onTouchEvent UP", "converted to CANCEL after long press")
|
||||
}
|
||||
return@intercept proceedWithCanceledAction(motionEvent) {
|
||||
chain.proceed()
|
||||
}.also {
|
||||
@@ -269,21 +255,12 @@ class NavButtons : XposedModule() {
|
||||
updateContextFromView(keyButtonView)
|
||||
performConfiguredAction(pressAction)
|
||||
}
|
||||
if (buttonId == NavButtonId.HOME) {
|
||||
traceHome(
|
||||
"KeyButtonView.onTouchEvent UP",
|
||||
"override=$shouldOverridePress ${systemUiHomeState(keyButtonView)}",
|
||||
)
|
||||
}
|
||||
cancelSystemUiHomeStockLongPressGuard(keyButtonView)
|
||||
systemUiHomeStockPressCanceled.remove(keyButtonView)
|
||||
result
|
||||
}
|
||||
|
||||
MotionEvent.ACTION_CANCEL -> {
|
||||
if (buttonId == NavButtonId.HOME) {
|
||||
traceHome("KeyButtonView.onTouchEvent CANCEL", "clearing long-press state")
|
||||
}
|
||||
cancelSystemUiHomeStockLongPressGuard(keyButtonView)
|
||||
systemUiLongPressTriggered.remove(keyButtonView)
|
||||
systemUiHomeStockPressCanceled.remove(keyButtonView)
|
||||
@@ -307,9 +284,6 @@ class NavButtons : XposedModule() {
|
||||
return@intercept chain.proceed()
|
||||
}
|
||||
|
||||
if (buttonId == NavButtonId.HOME) {
|
||||
traceHome("KeyButtonView\$1.run", "long=${longPressAction.storageValue}")
|
||||
}
|
||||
updateContextFromView(keyButtonView)
|
||||
systemUiLongPressTriggered[keyButtonView] = true
|
||||
cancelSystemUiKeyPress(keyButtonView)
|
||||
@@ -340,11 +314,6 @@ class NavButtons : XposedModule() {
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@@ -385,7 +354,6 @@ class NavButtons : XposedModule() {
|
||||
deoptimizeMethodIfPresent(longPressOnHomeWithEvent)
|
||||
hook(longPressOnHomeWithEvent).intercept { chain ->
|
||||
val longPressAction = getButtonConfig(NavButtonId.HOME).longPressAction
|
||||
traceHome("PhoneWindowManager.handleLongPressOnHome(KeyEvent)", "long=${longPressAction.storageValue}")
|
||||
if (longPressAction == NavButtonAction.STOCK) {
|
||||
return@intercept chain.proceed()
|
||||
}
|
||||
@@ -400,7 +368,6 @@ class NavButtons : XposedModule() {
|
||||
deoptimizeMethodIfPresent(longPressOnHomeLegacy)
|
||||
hook(longPressOnHomeLegacy).intercept { chain ->
|
||||
val longPressAction = getButtonConfig(NavButtonId.HOME).longPressAction
|
||||
traceHome("PhoneWindowManager.handleLongPressOnHome(int,long)", "long=${longPressAction.storageValue}")
|
||||
if (longPressAction == NavButtonAction.STOCK) {
|
||||
return@intercept chain.proceed()
|
||||
}
|
||||
@@ -415,7 +382,6 @@ class NavButtons : XposedModule() {
|
||||
deoptimizeMethodIfPresent(launchAssistActionMethod)
|
||||
hook(launchAssistActionMethod).intercept { chain ->
|
||||
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) {
|
||||
return@intercept chain.proceed()
|
||||
}
|
||||
@@ -425,7 +391,6 @@ class NavButtons : XposedModule() {
|
||||
return@intercept chain.proceed()
|
||||
}
|
||||
|
||||
traceHome("PhoneWindowManager.launchAssistAction", "blocked long=${longPressAction.storageValue}")
|
||||
updateContextFromField(chain.thisObject, "mContext")
|
||||
performHomeLongPressAction(longPressAction)
|
||||
null
|
||||
@@ -503,13 +468,6 @@ class NavButtons : XposedModule() {
|
||||
honeyspaceLongPressTriggered[navButtonView] = false
|
||||
cancelHoneyspaceHomeStockLongPressGuard(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()
|
||||
rescheduleHoneyspaceLongPress(navButtonView, runnableClass, buttonId)
|
||||
scheduleHoneyspaceHomeStockLongPressGuard(navButtonView, buttonId)
|
||||
@@ -519,9 +477,6 @@ class NavButtons : XposedModule() {
|
||||
MotionEvent.ACTION_UP -> {
|
||||
val longPressTriggered = honeyspaceLongPressTriggered[navButtonView] == true
|
||||
if (longPressTriggered) {
|
||||
if (buttonId == NavButtonId.HOME) {
|
||||
traceHome("Honeyspace.onTouchEvent UP", "converted to CANCEL after long press")
|
||||
}
|
||||
return@intercept proceedWithCanceledAction(motionEvent) {
|
||||
chain.proceed()
|
||||
}.also {
|
||||
@@ -554,19 +509,10 @@ class NavButtons : XposedModule() {
|
||||
cancelHoneyspaceHomeStockLongPressGuard(navButtonView)
|
||||
honeyspaceLongPressTriggered.remove(navButtonView)
|
||||
honeyspaceHomeStockPressCanceled.remove(navButtonView)
|
||||
if (buttonId == NavButtonId.HOME) {
|
||||
traceHome(
|
||||
"Honeyspace.onTouchEvent UP",
|
||||
"override=$shouldOverridePress ${honeyspaceHomeState(navButtonView)}",
|
||||
)
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
MotionEvent.ACTION_CANCEL -> {
|
||||
if (buttonId == NavButtonId.HOME) {
|
||||
traceHome("Honeyspace.onTouchEvent CANCEL", "clearing long-press state")
|
||||
}
|
||||
cancelHoneyspaceHomeStockLongPressGuard(navButtonView)
|
||||
honeyspaceLongPressTriggered.remove(navButtonView)
|
||||
honeyspaceHomeStockPressCanceled.remove(navButtonView)
|
||||
@@ -601,9 +547,6 @@ class NavButtons : XposedModule() {
|
||||
return@intercept chain.proceed()
|
||||
}
|
||||
|
||||
if (buttonId == NavButtonId.HOME) {
|
||||
traceHome("Honeyspace runnable", "long=${longPressAction.storageValue}")
|
||||
}
|
||||
updateContextFromView(navButtonView)
|
||||
markHoneyspaceLongClicked(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) {
|
||||
try {
|
||||
applyNativeHoneyspaceSideArrows(container, reason)
|
||||
@@ -1491,14 +1422,9 @@ class NavButtons : XposedModule() {
|
||||
}
|
||||
|
||||
private fun configureFoldedSideArrowButtons(navBarView: Any) {
|
||||
if (!isSideArrowsEnabled()) {
|
||||
return
|
||||
if (isSideArrowsEnabled()) {
|
||||
configureSideArrowDispatcherButtons(navBarView, navBarView)
|
||||
}
|
||||
|
||||
if (!configureSideArrowDispatcherButtons(navBarView, navBarView)) {
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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) {
|
||||
log(Log.INFO, TAG, message)
|
||||
}
|
||||
@@ -1945,11 +1850,9 @@ class NavButtons : XposedModule() {
|
||||
|
||||
private fun performHomeLongPressAction(action: NavButtonAction) {
|
||||
if (wasHomeLongPressHandledRecently()) {
|
||||
traceHome("performHomeLongPressAction", "deduped action=${action.storageValue}")
|
||||
return
|
||||
}
|
||||
noteHomeLongPressHandled()
|
||||
traceHome("performHomeLongPressAction", "executing action=${action.storageValue}")
|
||||
performConfiguredAction(action)
|
||||
}
|
||||
|
||||
@@ -1957,46 +1860,52 @@ class NavButtons : XposedModule() {
|
||||
if (buttonIdForKeyCode(getIntField(keyButtonView, "mCode")) == NavButtonId.HOME &&
|
||||
systemUiHomeStockPressCanceled[keyButtonView] == true
|
||||
) {
|
||||
traceHome("cancelSystemUiKeyPress", "stock key was already canceled by guard")
|
||||
abortSystemUiKeyGesture(keyButtonView)
|
||||
return
|
||||
}
|
||||
|
||||
traceHome("cancelSystemUiKeyPress", "sending canceled key-up")
|
||||
abortSystemUiKeyGesture(keyButtonView)
|
||||
sendSystemUiCanceledKeyUp(keyButtonView)
|
||||
}
|
||||
|
||||
private fun scheduleSystemUiHomeStockLongPressGuard(keyButtonView: Any, buttonId: NavButtonId) {
|
||||
if (buttonId != NavButtonId.HOME) {
|
||||
return
|
||||
}
|
||||
if (getButtonConfig(buttonId).longPressAction == NavButtonAction.STOCK) {
|
||||
return
|
||||
}
|
||||
|
||||
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())
|
||||
scheduleHomeStockLongPressGuard(
|
||||
keyButtonView,
|
||||
buttonId,
|
||||
systemUiHomeStockLongPressGuards,
|
||||
systemUiLongPressTriggered,
|
||||
systemUiHomeStockPressCanceled,
|
||||
::sendSystemUiCanceledKeyUp,
|
||||
)
|
||||
}
|
||||
|
||||
private fun cancelSystemUiHomeStockLongPressGuard(keyButtonView: Any) {
|
||||
val guard = systemUiHomeStockLongPressGuards.remove(keyButtonView) ?: return
|
||||
(keyButtonView as? View)?.removeCallbacks(guard)
|
||||
cancelHomeStockLongPressGuard(keyButtonView, systemUiHomeStockLongPressGuards)
|
||||
}
|
||||
|
||||
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) {
|
||||
return
|
||||
}
|
||||
@@ -2004,25 +1913,24 @@ class NavButtons : XposedModule() {
|
||||
return
|
||||
}
|
||||
|
||||
val view = navButtonView as? View ?: return
|
||||
val view = target 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 || honeyspaceLongPressTriggered[navButtonView] == true) {
|
||||
if (!view.isPressed || longPressTriggered[target] == true) {
|
||||
return@Runnable
|
||||
}
|
||||
traceHome("Honeyspace stock long-press guard", "canceling original Home key after ${delayMs}ms")
|
||||
honeyspaceHomeStockPressCanceled[navButtonView] = true
|
||||
sendHoneyspaceCanceledKeyUp(navButtonView)
|
||||
stockPressCanceled[target] = true
|
||||
sendCanceledKeyUp(target)
|
||||
}
|
||||
|
||||
honeyspaceHomeStockLongPressGuards[navButtonView] = guard
|
||||
guards[target] = guard
|
||||
view.postDelayed(guard, delayMs.toLong())
|
||||
}
|
||||
|
||||
private fun cancelHoneyspaceHomeStockLongPressGuard(navButtonView: Any) {
|
||||
val guard = honeyspaceHomeStockLongPressGuards.remove(navButtonView) ?: return
|
||||
(navButtonView as? View)?.removeCallbacks(guard)
|
||||
private fun cancelHomeStockLongPressGuard(target: Any, guards: WeakHashMap<Any, Runnable>) {
|
||||
val guard = guards.remove(target) ?: return
|
||||
(target as? View)?.removeCallbacks(guard)
|
||||
}
|
||||
|
||||
private fun abortSystemUiKeyGesture(keyButtonView: Any) {
|
||||
@@ -2087,7 +1995,6 @@ class NavButtons : XposedModule() {
|
||||
}
|
||||
|
||||
private fun dispatchSystemUiHomeTap(keyButtonView: Any) {
|
||||
traceHome("dispatchSystemUiHomeTap", "sending stock tap after guard cancel")
|
||||
try {
|
||||
callMethod(
|
||||
keyButtonView,
|
||||
@@ -2109,7 +2016,6 @@ class NavButtons : XposedModule() {
|
||||
}
|
||||
|
||||
private fun dispatchHoneyspaceHomeTap(navButtonView: Any) {
|
||||
traceHome("dispatchHoneyspaceHomeTap", "sending stock tap after guard cancel")
|
||||
if (callIntIntMethodIfExists(navButtonView, listOf("sendEvent", "sendKeyEvent"), KeyEvent.ACTION_DOWN, 0) &&
|
||||
callIntIntMethodIfExists(navButtonView, listOf("sendEvent", "sendKeyEvent"), KeyEvent.ACTION_UP, 0)
|
||||
) {
|
||||
@@ -2220,32 +2126,6 @@ class NavButtons : XposedModule() {
|
||||
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 {
|
||||
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 {
|
||||
return this and flag == flag
|
||||
}
|
||||
@@ -2450,7 +2307,6 @@ class NavButtons : XposedModule() {
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val DEBUG_TRACE = false
|
||||
const val TAG = "NavButtons"
|
||||
const val ASSIST_INVOCATION_TYPE_UNKNOWN = 0
|
||||
const val ASSIST_INVOCATION_TYPE_HOME_BUTTON_LONG_PRESS = 5
|
||||
|
||||
@@ -22,7 +22,6 @@ import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import java.text.DecimalFormatSymbols
|
||||
import java.util.Locale
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class SettingsActivity : Activity() {
|
||||
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(
|
||||
sectionView: View,
|
||||
private val buttonId: NavButtonId,
|
||||
@@ -188,7 +233,7 @@ class SettingsActivity : Activity() {
|
||||
applyDuration(config.longPressDurationMs, persist = false)
|
||||
bindDurationInput()
|
||||
bindStepButtons()
|
||||
bindTestButton()
|
||||
attachTestButton(testButton, ::resolveDurationForUse)
|
||||
}
|
||||
|
||||
private fun bindActionSpinner(
|
||||
@@ -196,27 +241,12 @@ class SettingsActivity : Activity() {
|
||||
selectedAction: NavButtonAction,
|
||||
storeAction: (NavButtonId, NavButtonAction) -> Unit,
|
||||
) {
|
||||
val labels = NavButtonAction.entries.map { getString(it.labelRes) }
|
||||
val adapter = ArrayAdapter(
|
||||
this@SettingsActivity,
|
||||
R.layout.item_spinner_selected,
|
||||
labels,
|
||||
)
|
||||
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
|
||||
}
|
||||
bindSpinner(
|
||||
spinner,
|
||||
NavButtonAction.entries,
|
||||
selectedAction,
|
||||
NavButtonAction::labelRes,
|
||||
) { action -> storeAction(buttonId, action) }
|
||||
}
|
||||
|
||||
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) {
|
||||
val current = resolveDurationForUse()
|
||||
val updated = (current + deltaMs).coerceIn(
|
||||
@@ -344,8 +352,6 @@ class SettingsActivity : Activity() {
|
||||
private val durationPlusButton: Button =
|
||||
sectionView.findViewById(R.id.side_arrow_duration_plus_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 var lastValidDurationMs = settingsStore.defaultLongPressDurationMs()
|
||||
@@ -362,7 +368,7 @@ class SettingsActivity : Activity() {
|
||||
applyDuration(settingsStore.getSideArrowLongPressDurationMs(), persist = false)
|
||||
bindDurationInput()
|
||||
bindDurationButtons()
|
||||
bindTestButton()
|
||||
attachTestButton(testButton, ::resolveDurationForUse)
|
||||
updateOptionsEnabled()
|
||||
|
||||
sideArrowsCheckbox.setOnCheckedChangeListener { _, isChecked ->
|
||||
@@ -375,49 +381,17 @@ 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() {
|
||||
val labels = SideArrowLongPressAction.entries.map { getString(it.labelRes) }
|
||||
val adapter = ArrayAdapter(
|
||||
this@SettingsActivity,
|
||||
R.layout.item_spinner_selected,
|
||||
labels,
|
||||
)
|
||||
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]
|
||||
bindSpinner(
|
||||
longPressActionSpinner,
|
||||
SideArrowLongPressAction.entries,
|
||||
settingsStore.getSideArrowLongPressAction(),
|
||||
SideArrowLongPressAction::labelRes,
|
||||
) { action ->
|
||||
settingsStore.setSideArrowLongPressAction(action)
|
||||
updateRepeatSpeedVisibility(action)
|
||||
}
|
||||
|
||||
override fun onNothingSelected(parent: AdapterView<*>?) = Unit
|
||||
}
|
||||
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() {
|
||||
val enabled = sideArrowsCheckbox.isChecked
|
||||
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>
|
||||
|
||||
<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>
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
<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_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="long_press_action_label">When long-pressed</string>
|
||||
<string name="long_press_duration_label">Long-press duration (ms)</string>
|
||||
|
||||
Reference in New Issue
Block a user