Fix Samsung unfolded long presses
This commit is contained in:
@@ -31,7 +31,7 @@ internal class ActionExecutor(
|
|||||||
NavButtonAction.ASSISTANT -> sendConfiguredKeyPress(KeyEvent.KEYCODE_ASSIST)
|
NavButtonAction.ASSISTANT -> sendConfiguredKeyPress(KeyEvent.KEYCODE_ASSIST)
|
||||||
NavButtonAction.RECENTS -> sendConfiguredKeyPress(KeyEvent.KEYCODE_APP_SWITCH)
|
NavButtonAction.RECENTS -> sendConfiguredKeyPress(KeyEvent.KEYCODE_APP_SWITCH)
|
||||||
NavButtonAction.KILL_FOREGROUND_APP -> performPrivilegedActionOrDirect(PRIVILEGED_ACTION_KILL_FOREGROUND_APP)
|
NavButtonAction.KILL_FOREGROUND_APP -> performPrivilegedActionOrDirect(PRIVILEGED_ACTION_KILL_FOREGROUND_APP)
|
||||||
NavButtonAction.TOGGLE_AUTO_ROTATE -> toggleAutoRotate()
|
NavButtonAction.TOGGLE_AUTO_ROTATE -> performPrivilegedActionOrDirect(PRIVILEGED_ACTION_TOGGLE_AUTO_ROTATE)
|
||||||
NavButtonAction.TOGGLE_FLASHLIGHT -> performPrivilegedActionOrDirect(PRIVILEGED_ACTION_TOGGLE_FLASHLIGHT)
|
NavButtonAction.TOGGLE_FLASHLIGHT -> performPrivilegedActionOrDirect(PRIVILEGED_ACTION_TOGGLE_FLASHLIGHT)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -120,13 +120,14 @@ internal class ActionExecutor(
|
|||||||
when (action) {
|
when (action) {
|
||||||
PRIVILEGED_ACTION_KILL_FOREGROUND_APP -> killForegroundApp()
|
PRIVILEGED_ACTION_KILL_FOREGROUND_APP -> killForegroundApp()
|
||||||
PRIVILEGED_ACTION_TOGGLE_FLASHLIGHT -> toggleFlashlight()
|
PRIVILEGED_ACTION_TOGGLE_FLASHLIGHT -> toggleFlashlight()
|
||||||
|
PRIVILEGED_ACTION_TOGGLE_AUTO_ROTATE -> toggleAutoRotate()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
requestPrivilegedAction(action, null)
|
requestPrivilegedAction(action, null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun toggleAutoRotate() {
|
fun toggleAutoRotate() {
|
||||||
val context = contextProvider() ?: run {
|
val context = contextProvider() ?: run {
|
||||||
log("Context unavailable, cannot toggle auto rotate.")
|
log("Context unavailable, cannot toggle auto rotate.")
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ internal const val EXTRA_PRIVILEGED_ACTION_TOKEN = "privileged_action_token"
|
|||||||
internal const val EXTRA_PRIVILEGED_KEY_CODE = "privileged_key_code"
|
internal const val EXTRA_PRIVILEGED_KEY_CODE = "privileged_key_code"
|
||||||
internal const val PRIVILEGED_ACTION_KILL_FOREGROUND_APP = "kill_foreground_app"
|
internal const val PRIVILEGED_ACTION_KILL_FOREGROUND_APP = "kill_foreground_app"
|
||||||
internal const val PRIVILEGED_ACTION_TOGGLE_FLASHLIGHT = "toggle_flashlight"
|
internal const val PRIVILEGED_ACTION_TOGGLE_FLASHLIGHT = "toggle_flashlight"
|
||||||
|
internal const val PRIVILEGED_ACTION_TOGGLE_AUTO_ROTATE = "toggle_auto_rotate"
|
||||||
internal const val PRIVILEGED_ACTION_SEND_KEY_PRESS = "send_key_press"
|
internal const val PRIVILEGED_ACTION_SEND_KEY_PRESS = "send_key_press"
|
||||||
|
|
||||||
internal const val HONEYSPACE_NAV_BUTTON_VIEW =
|
internal const val HONEYSPACE_NAV_BUTTON_VIEW =
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ class NavButtons() : XposedModule() {
|
|||||||
},
|
},
|
||||||
killForegroundApp = actions::killForegroundApp,
|
killForegroundApp = actions::killForegroundApp,
|
||||||
toggleFlashlight = actions::toggleFlashlight,
|
toggleFlashlight = actions::toggleFlashlight,
|
||||||
|
toggleAutoRotate = actions::toggleAutoRotate,
|
||||||
sendKeyPress = actions::sendKeyPress,
|
sendKeyPress = actions::sendKeyPress,
|
||||||
)
|
)
|
||||||
private val sideArrowLongPresses: SideArrowLongPressController = SideArrowLongPressController(
|
private val sideArrowLongPresses: SideArrowLongPressController = SideArrowLongPressController(
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ internal class PrivilegedActionBridge(
|
|||||||
private val log: (String, Throwable?) -> Unit,
|
private val log: (String, Throwable?) -> Unit,
|
||||||
private val killForegroundApp: () -> Unit,
|
private val killForegroundApp: () -> Unit,
|
||||||
private val toggleFlashlight: () -> Unit,
|
private val toggleFlashlight: () -> Unit,
|
||||||
|
private val toggleAutoRotate: () -> Unit,
|
||||||
private val sendKeyPress: (Int) -> Unit,
|
private val sendKeyPress: (Int) -> Unit,
|
||||||
) {
|
) {
|
||||||
private var receiverRegistered = false
|
private var receiverRegistered = false
|
||||||
@@ -78,6 +79,7 @@ internal class PrivilegedActionBridge(
|
|||||||
when (action) {
|
when (action) {
|
||||||
PRIVILEGED_ACTION_KILL_FOREGROUND_APP -> killForegroundApp()
|
PRIVILEGED_ACTION_KILL_FOREGROUND_APP -> killForegroundApp()
|
||||||
PRIVILEGED_ACTION_TOGGLE_FLASHLIGHT -> toggleFlashlight()
|
PRIVILEGED_ACTION_TOGGLE_FLASHLIGHT -> toggleFlashlight()
|
||||||
|
PRIVILEGED_ACTION_TOGGLE_AUTO_ROTATE -> toggleAutoRotate()
|
||||||
PRIVILEGED_ACTION_SEND_KEY_PRESS -> {
|
PRIVILEGED_ACTION_SEND_KEY_PRESS -> {
|
||||||
if (keyCode != KeyEvent.KEYCODE_UNKNOWN) {
|
if (keyCode != KeyEvent.KEYCODE_UNKNOWN) {
|
||||||
sendKeyPress(keyCode)
|
sendKeyPress(keyCode)
|
||||||
@@ -92,12 +94,12 @@ internal class PrivilegedActionBridge(
|
|||||||
senderPackage: String?,
|
senderPackage: String?,
|
||||||
senderUid: Int,
|
senderUid: Int,
|
||||||
): Boolean {
|
): Boolean {
|
||||||
if (senderPackage == SYSTEMUI_PACKAGE || senderPackage in AOSP_LAUNCHER_PACKAGES) {
|
if (isTrustedUiPackage(senderPackage)) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
val caller = getParcelableExtraCompat(intent, EXTRA_PRIVILEGED_CALLER, PendingIntent::class.java)
|
val caller = getParcelableExtraCompat(intent, EXTRA_PRIVILEGED_CALLER, PendingIntent::class.java)
|
||||||
if (caller?.creatorPackage == SYSTEMUI_PACKAGE || caller?.creatorPackage in AOSP_LAUNCHER_PACKAGES) {
|
if (isTrustedUiPackage(caller?.creatorPackage)) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if (caller?.creatorUid == Process.SYSTEM_UID) {
|
if (caller?.creatorUid == Process.SYSTEM_UID) {
|
||||||
@@ -117,7 +119,13 @@ internal class PrivilegedActionBridge(
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return context.packageManager.getPackagesForUid(senderUid)
|
return context.packageManager.getPackagesForUid(senderUid)
|
||||||
?.any { it == SYSTEMUI_PACKAGE || it in AOSP_LAUNCHER_PACKAGES } == true
|
?.any(::isTrustedUiPackage) == true
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isTrustedUiPackage(packageName: String?): Boolean {
|
||||||
|
return packageName == SYSTEMUI_PACKAGE ||
|
||||||
|
packageName == SAMSUNG_LAUNCHER_PACKAGE ||
|
||||||
|
packageName in AOSP_LAUNCHER_PACKAGES
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun readToken(): String? {
|
private fun readToken(): String? {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package se.ajpanton.navbuttons
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.SystemClock
|
import android.os.SystemClock
|
||||||
|
import android.view.HapticFeedbackConstants
|
||||||
import android.view.KeyEvent
|
import android.view.KeyEvent
|
||||||
import android.view.MotionEvent
|
import android.view.MotionEvent
|
||||||
import android.view.View
|
import android.view.View
|
||||||
@@ -28,6 +29,7 @@ internal class SamsungHoneyspaceHooks(
|
|||||||
private val log: (String) -> Unit,
|
private val log: (String) -> Unit,
|
||||||
) {
|
) {
|
||||||
private val longPressTriggered = WeakHashMap<Any, Boolean>()
|
private val longPressTriggered = WeakHashMap<Any, Boolean>()
|
||||||
|
private val customLongPressRunnables = WeakHashMap<Any, Runnable>()
|
||||||
private val trackedNavContainers = Collections.newSetFromMap(WeakHashMap<Any, Boolean>())
|
private val trackedNavContainers = Collections.newSetFromMap(WeakHashMap<Any, Boolean>())
|
||||||
private val nativeSideArrowStates = WeakHashMap<Any, Boolean>()
|
private val nativeSideArrowStates = WeakHashMap<Any, Boolean>()
|
||||||
private val homeStockLongPressGuard = HomeStockLongPressGuard(
|
private val homeStockLongPressGuard = HomeStockLongPressGuard(
|
||||||
@@ -86,20 +88,26 @@ internal class SamsungHoneyspaceHooks(
|
|||||||
when (motionEvent.actionMasked) {
|
when (motionEvent.actionMasked) {
|
||||||
MotionEvent.ACTION_DOWN -> {
|
MotionEvent.ACTION_DOWN -> {
|
||||||
longPressTriggered[navButtonView] = false
|
longPressTriggered[navButtonView] = false
|
||||||
|
cancelCustomLongPress(navButtonView)
|
||||||
homeStockLongPressGuard.cancel(navButtonView)
|
homeStockLongPressGuard.cancel(navButtonView)
|
||||||
homeStockLongPressGuard.clear(navButtonView)
|
homeStockLongPressGuard.clear(navButtonView)
|
||||||
val result = chain.proceed()
|
val result = chain.proceed()
|
||||||
rescheduleHoneyspaceLongPress(
|
val config = configProvider(buttonId)
|
||||||
|
if (config.longPressAction != NavButtonAction.STOCK) {
|
||||||
|
cancelHoneyspaceLongPress(navButtonView, runnableClass)
|
||||||
|
scheduleCustomLongPress(
|
||||||
navButtonView,
|
navButtonView,
|
||||||
runnableClass,
|
config.longPressAction,
|
||||||
configProvider(buttonId).longPressDurationMs,
|
config.longPressDurationMs,
|
||||||
)
|
)
|
||||||
|
}
|
||||||
homeStockLongPressGuard.schedule(navButtonView, buttonId)
|
homeStockLongPressGuard.schedule(navButtonView, buttonId)
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
MotionEvent.ACTION_UP -> {
|
MotionEvent.ACTION_UP -> {
|
||||||
val triggered = longPressTriggered[navButtonView] == true
|
val triggered = longPressTriggered[navButtonView] == true
|
||||||
|
cancelCustomLongPress(navButtonView)
|
||||||
if (triggered) {
|
if (triggered) {
|
||||||
return@hookMethod proceedWithCanceledAction(motionEvent) {
|
return@hookMethod proceedWithCanceledAction(motionEvent) {
|
||||||
chain.proceed()
|
chain.proceed()
|
||||||
@@ -137,6 +145,7 @@ internal class SamsungHoneyspaceHooks(
|
|||||||
}
|
}
|
||||||
|
|
||||||
MotionEvent.ACTION_CANCEL -> {
|
MotionEvent.ACTION_CANCEL -> {
|
||||||
|
cancelCustomLongPress(navButtonView)
|
||||||
homeStockLongPressGuard.cancel(navButtonView)
|
homeStockLongPressGuard.cancel(navButtonView)
|
||||||
longPressTriggered.remove(navButtonView)
|
longPressTriggered.remove(navButtonView)
|
||||||
homeStockLongPressGuard.clear(navButtonView)
|
homeStockLongPressGuard.clear(navButtonView)
|
||||||
@@ -179,6 +188,30 @@ internal class SamsungHoneyspaceHooks(
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun scheduleCustomLongPress(
|
||||||
|
navButtonView: Any,
|
||||||
|
action: NavButtonAction,
|
||||||
|
durationMs: Int,
|
||||||
|
) {
|
||||||
|
val view = navButtonView as? View ?: return
|
||||||
|
val runnable = Runnable {
|
||||||
|
updateContextFromView(navButtonView)
|
||||||
|
longPressTriggered[navButtonView] = true
|
||||||
|
markLongClicked(navButtonView)
|
||||||
|
homeStockLongPressGuard.cancel(navButtonView)
|
||||||
|
view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS)
|
||||||
|
performAction(action)
|
||||||
|
}
|
||||||
|
customLongPressRunnables[navButtonView] = runnable
|
||||||
|
view.postDelayed(runnable, durationMs.toLong())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun cancelCustomLongPress(navButtonView: Any) {
|
||||||
|
customLongPressRunnables.remove(navButtonView)?.let { runnable ->
|
||||||
|
(navButtonView as? View)?.removeCallbacks(runnable)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun refreshSideArrowLayouts(reason: String) {
|
fun refreshSideArrowLayouts(reason: String) {
|
||||||
val containers = trackedNavContainers.toList()
|
val containers = trackedNavContainers.toList()
|
||||||
containers.forEach { container ->
|
containers.forEach { container ->
|
||||||
|
|||||||
@@ -48,15 +48,10 @@ internal fun isHoneyspaceNavButtonContainer(view: View): Boolean {
|
|||||||
honeyspaceViewIdName(view) == "navbar_button_container"
|
honeyspaceViewIdName(view) == "navbar_button_container"
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun rescheduleHoneyspaceLongPress(
|
internal fun cancelHoneyspaceLongPress(navButtonView: Any, runnableClass: Class<*>) {
|
||||||
navButtonView: Any,
|
|
||||||
runnableClass: Class<*>,
|
|
||||||
durationMs: Int,
|
|
||||||
) {
|
|
||||||
val view = navButtonView as? View ?: return
|
val view = navButtonView as? View ?: return
|
||||||
val longPressRunnable = findHoneyspaceLongPressRunnable(navButtonView, runnableClass) ?: return
|
val longPressRunnable = findHoneyspaceLongPressRunnable(navButtonView, runnableClass) ?: return
|
||||||
view.removeCallbacks(longPressRunnable)
|
view.removeCallbacks(longPressRunnable)
|
||||||
view.postDelayed(longPressRunnable, durationMs.toLong())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun createHoneyspaceExtraButton(
|
internal fun createHoneyspaceExtraButton(
|
||||||
|
|||||||
Reference in New Issue
Block a user