Add initial AOSP button support

This commit is contained in:
ajp_anton
2026-06-22 11:31:13 +00:00
parent e9686f6cb3
commit 1fc63aef8d
4 changed files with 512 additions and 0 deletions
+5
View File
@@ -3,6 +3,11 @@
xmlns:tools="http://schemas.android.com/tools"> xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" /> <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />
<queries>
<package android:name="org.lsposed.manager" />
</queries>
<application <application
android:allowBackup="true" android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules" android:dataExtractionRules="@xml/data_extraction_rules"
@@ -7,6 +7,7 @@ import android.view.ViewConfiguration
import androidx.annotation.StringRes import androidx.annotation.StringRes
import io.github.libxposed.service.XposedService import io.github.libxposed.service.XposedService
import io.github.libxposed.service.XposedServiceHelper import io.github.libxposed.service.XposedServiceHelper
import java.util.UUID
enum class NavButtonId( enum class NavButtonId(
val preferencePrefix: String, val preferencePrefix: String,
@@ -68,6 +69,7 @@ class NavButtonSettingsStore(context: Context) {
) )
init { init {
ensurePrivilegedActionToken()
registerRemotePreferencesListener(localPreferences) registerRemotePreferencesListener(localPreferences)
} }
@@ -197,6 +199,15 @@ class NavButtonSettingsStore(context: Context) {
} }
} }
private fun ensurePrivilegedActionToken() {
if (localPreferences.contains(KEY_PRIVILEGED_ACTION_TOKEN)) {
return
}
writeToPreferences(localPreferences, System.currentTimeMillis()) {
putString(KEY_PRIVILEGED_ACTION_TOKEN, UUID.randomUUID().toString())
}
}
private fun writeToPreferences( private fun writeToPreferences(
preferences: SharedPreferences, preferences: SharedPreferences,
updatedAtMs: Long, updatedAtMs: Long,
@@ -220,6 +231,7 @@ class NavButtonSettingsStore(context: Context) {
const val KEY_SIDE_ARROW_LONG_PRESS_ACTION = "side_arrow_long_press_action" const val KEY_SIDE_ARROW_LONG_PRESS_ACTION = "side_arrow_long_press_action"
const val KEY_SIDE_ARROW_REPEAT_STEPS_PER_SECOND = "side_arrow_repeat_steps_per_second" const val KEY_SIDE_ARROW_REPEAT_STEPS_PER_SECOND = "side_arrow_repeat_steps_per_second"
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"
const val KEY_PRIVILEGED_ACTION_TOKEN = "privileged_action_token"
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_DURATION_MS = 100 const val MIN_DURATION_MS = 100
@@ -358,6 +370,12 @@ class NavButtonSettingsStore(context: Context) {
editor.remove(KEY_SIDE_ARROWS_ENABLED) editor.remove(KEY_SIDE_ARROWS_ENABLED)
} }
if (source.contains(KEY_PRIVILEGED_ACTION_TOKEN)) {
editor.putString(KEY_PRIVILEGED_ACTION_TOKEN, source.getString(KEY_PRIVILEGED_ACTION_TOKEN, null))
} else {
editor.remove(KEY_PRIVILEGED_ACTION_TOKEN)
}
if (source.contains(KEY_LAST_UPDATED_AT_MS)) { if (source.contains(KEY_LAST_UPDATED_AT_MS)) {
editor.putLong(KEY_LAST_UPDATED_AT_MS, source.getLong(KEY_LAST_UPDATED_AT_MS, 0L)) editor.putLong(KEY_LAST_UPDATED_AT_MS, source.getLong(KEY_LAST_UPDATED_AT_MS, 0L))
} else { } else {
@@ -22,12 +22,15 @@ import android.graphics.drawable.Drawable
import android.hardware.camera2.CameraAccessException import android.hardware.camera2.CameraAccessException
import android.hardware.camera2.CameraCharacteristics import android.hardware.camera2.CameraCharacteristics
import android.hardware.camera2.CameraManager import android.hardware.camera2.CameraManager
import android.os.Build
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
import android.view.InputEvent import android.view.InputEvent
import android.view.HapticFeedbackConstants
import android.view.KeyEvent import android.view.KeyEvent
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.MotionEvent import android.view.MotionEvent
@@ -59,12 +62,18 @@ class NavButtons : XposedModule() {
private var systemUiHookInstalled = false private var systemUiHookInstalled = false
private var systemServerHookInstalled = false private var systemServerHookInstalled = false
private var launcherHookInstalled = false private var launcherHookInstalled = false
private var aospTaskbarHookInstalled = false
private var lastHomeLongPressHandledAtMs = 0L private var lastHomeLongPressHandledAtMs = 0L
private var flashlightCameraId: String? = null private var flashlightCameraId: String? = null
private var flashlightEnabled = false private var flashlightEnabled = false
private val systemUiLongPressTriggered = WeakHashMap<Any, Boolean>() private val systemUiLongPressTriggered = WeakHashMap<Any, Boolean>()
private val systemUiHomeStockLongPressGuards = WeakHashMap<Any, Runnable>() private val systemUiHomeStockLongPressGuards = WeakHashMap<Any, Runnable>()
private val systemUiHomeStockPressCanceled = WeakHashMap<Any, Boolean>() private val systemUiHomeStockPressCanceled = WeakHashMap<Any, Boolean>()
private val aospTaskbarButtonIds = WeakHashMap<Any, NavButtonId>()
private val aospTaskbarControllers = WeakHashMap<Any, Any>()
private val aospTaskbarLongPressRunnables = WeakHashMap<Any, Runnable>()
private val aospTaskbarLongPressTriggered = WeakHashMap<Any, Boolean>()
private val aospTaskbarBackLongPressTriggered = WeakHashMap<Any, Boolean>()
private val honeyspaceLongPressTriggered = WeakHashMap<Any, Boolean>() private val honeyspaceLongPressTriggered = WeakHashMap<Any, Boolean>()
private val honeyspaceHomeStockLongPressGuards = WeakHashMap<Any, Runnable>() private val honeyspaceHomeStockLongPressGuards = WeakHashMap<Any, Runnable>()
private val honeyspaceHomeStockPressCanceled = WeakHashMap<Any, Boolean>() private val honeyspaceHomeStockPressCanceled = WeakHashMap<Any, Boolean>()
@@ -78,6 +87,8 @@ class NavButtons : XposedModule() {
private var foldedSideArrowProviderHookInstalled = false private var foldedSideArrowProviderHookInstalled = false
private var samsungNavigationBarViewHookInstalled = false private var samsungNavigationBarViewHookInstalled = false
private var settingsChangedReceiverRegistered = false private var settingsChangedReceiverRegistered = false
private var privilegedActionReceiverRegistered = false
private var privilegedActionToken: String? = null
private var sideArrowsEnabledOverride: Boolean? = null private var sideArrowsEnabledOverride: Boolean? = null
override fun onModuleLoaded(param: XposedModuleInterface.ModuleLoadedParam) { override fun onModuleLoaded(param: XposedModuleInterface.ModuleLoadedParam) {
@@ -121,6 +132,14 @@ class NavButtons : XposedModule() {
return return
} }
if (AOSP_LAUNCHER_PACKAGE == packageName) {
if (aospTaskbarHookInstalled) {
return
}
initContextAndHandler()
aospTaskbarHookInstalled = hookAospTaskbar(classLoader)
return
}
} }
private fun initContextAndHandler() { private fun initContextAndHandler() {
@@ -349,6 +368,18 @@ class NavButtons : XposedModule() {
Long::class.javaPrimitiveType!!, Long::class.javaPrimitiveType!!,
Int::class.javaPrimitiveType!!, Int::class.javaPrimitiveType!!,
) )
val systemReadyMethod = findMethodIfExists(phoneWindowManagerClass, "systemReady")
if (systemReadyMethod != null) {
deoptimizeMethodIfPresent(systemReadyMethod)
hook(systemReadyMethod).intercept { chain ->
val result = chain.proceed()
updateContextFromField(chain.thisObject, "mContext")
registerPrivilegedActionReceiver()
result
}
installed = true
}
if (longPressOnHomeWithEvent != null) { if (longPressOnHomeWithEvent != null) {
deoptimizeMethodIfPresent(longPressOnHomeWithEvent) deoptimizeMethodIfPresent(longPressOnHomeWithEvent)
@@ -400,6 +431,253 @@ class NavButtons : XposedModule() {
return installed return installed
} }
private fun hookAospTaskbar(classLoader: ClassLoader?): Boolean {
val controllerClass = findClassIfExists(AOSP_TASKBAR_NAV_BUTTON_CONTROLLER, classLoader) ?: run {
log("AOSP taskbar controller class not found: $AOSP_TASKBAR_NAV_BUTTON_CONTROLLER")
return false
}
val navButtonsViewControllerClass = findClassIfExists(
AOSP_NAVBAR_BUTTONS_VIEW_CONTROLLER,
classLoader,
)
val clickMethod = findMethodIfExists(
controllerClass,
"onButtonClick",
Int::class.javaPrimitiveType!!,
View::class.java,
) ?: run {
log("AOSP taskbar onButtonClick() method not found.")
return false
}
val longClickMethod = findMethodIfExists(
controllerClass,
"onButtonLongClick",
Int::class.javaPrimitiveType!!,
View::class.java,
) ?: run {
log("AOSP taskbar onButtonLongClick() method not found.")
return false
}
val sendBackKeyEventMethod = findMethodIfExists(
controllerClass,
"sendBackKeyEvent",
Int::class.javaPrimitiveType!!,
Boolean::class.javaPrimitiveType!!,
) ?: run {
log("AOSP taskbar sendBackKeyEvent() method not found.")
return false
}
deoptimizeMethodIfPresent(clickMethod)
deoptimizeMethodIfPresent(longClickMethod)
deoptimizeMethodIfPresent(sendBackKeyEventMethod)
hookAospTaskbarButtonMapping(navButtonsViewControllerClass, controllerClass)
hookAospTaskbarTouchEvents()
hook(clickMethod).intercept { chain ->
val buttonId = buttonIdForAospTaskbarCode(chain.args[0] as? Int)
?: return@intercept chain.proceed()
val pressAction = getButtonConfig(buttonId).pressAction
if (pressAction == NavButtonAction.STOCK) {
return@intercept chain.proceed()
}
updateContextFromTaskbar(chain.thisObject, chain.args.getOrNull(1))
performAospTaskbarAction(chain.thisObject, pressAction)
null
}
hook(longClickMethod).intercept { chain ->
val buttonId = buttonIdForAospTaskbarCode(chain.args[0] as? Int)
?: return@intercept chain.proceed()
val longPressAction = getButtonConfig(buttonId).longPressAction
if (longPressAction == NavButtonAction.STOCK) {
return@intercept chain.proceed()
}
val view = chain.args.getOrNull(1)
if (view != null && aospTaskbarButtonIds.containsKey(view)) {
return@intercept true
}
updateContextFromTaskbar(chain.thisObject, chain.args.getOrNull(1))
if (buttonId == NavButtonId.HOME) {
performAospTaskbarHomeLongPressAction(chain.thisObject, longPressAction)
} else {
performAospTaskbarAction(chain.thisObject, longPressAction)
}
true
}
hook(sendBackKeyEventMethod).intercept { chain ->
val pressAction = getButtonConfig(NavButtonId.BACK).pressAction
val longPressAction = getButtonConfig(NavButtonId.BACK).longPressAction
val action = chain.args[0] as? Int ?: return@intercept chain.proceed()
val canceled = chain.args.getOrNull(1) as? Boolean ?: false
val customLongPress = longPressAction != NavButtonAction.STOCK
val longPressTriggered = aospTaskbarBackLongPressTriggered[chain.thisObject] == true
if (pressAction == NavButtonAction.STOCK && !customLongPress) {
return@intercept chain.proceed()
}
updateContextFromField(chain.thisObject, "mContext")
if (action == KeyEvent.ACTION_UP) {
aospTaskbarBackLongPressTriggered.remove(chain.thisObject)
}
if (customLongPress && action == KeyEvent.ACTION_DOWN) {
return@intercept null
}
if (action == KeyEvent.ACTION_UP && !canceled && !longPressTriggered) {
performAospTaskbarAction(
chain.thisObject,
if (pressAction == NavButtonAction.STOCK) NavButtonAction.BACK else pressAction,
)
}
null
}
return true
}
private fun hookAospTaskbarButtonMapping(
navButtonsViewControllerClass: Class<*>?,
controllerClass: Class<*>,
) {
if (navButtonsViewControllerClass == null) {
log("AOSP navbar buttons controller class not found: $AOSP_NAVBAR_BUTTONS_VIEW_CONTROLLER")
return
}
listOf(
arrayOf(
Int::class.javaPrimitiveType!!,
Int::class.javaPrimitiveType!!,
ViewGroup::class.java,
controllerClass,
Int::class.javaPrimitiveType!!,
),
arrayOf(
Int::class.javaPrimitiveType!!,
Int::class.javaPrimitiveType!!,
ViewGroup::class.java,
controllerClass,
Int::class.javaPrimitiveType!!,
Int::class.javaPrimitiveType!!,
),
).forEach { parameterTypes ->
val addButtonMethod = findMethodIfExists(
navButtonsViewControllerClass,
"addButton",
*parameterTypes,
) ?: return@forEach
deoptimizeMethodIfPresent(addButtonMethod)
hook(addButtonMethod).intercept { chain ->
val result = chain.proceed()
val view = result as? View ?: return@intercept result
trackAospTaskbarButton(
view,
chain.args.getOrNull(1) as? Int,
chain.args.getOrNull(3),
)
result
}
}
}
private fun hookAospTaskbarTouchEvents() {
val onTouchEventMethod = findMethodIfExists(
View::class.java,
"onTouchEvent",
MotionEvent::class.java,
) ?: run {
log("AOSP taskbar View.onTouchEvent() method not found.")
return
}
deoptimizeMethodIfPresent(onTouchEventMethod)
hook(onTouchEventMethod).intercept { chain ->
val view = chain.thisObject as? View ?: return@intercept chain.proceed()
val event = chain.args.getOrNull(0) as? MotionEvent ?: return@intercept chain.proceed()
val overrideResult = handleAospTaskbarTouch(view, event)
overrideResult ?: chain.proceed()
}
}
private fun trackAospTaskbarButton(view: View, buttonCode: Int?, controller: Any?) {
val buttonId = buttonIdForAospTaskbarCode(buttonCode) ?: return
aospTaskbarButtonIds[view] = buttonId
if (controller != null) {
aospTaskbarControllers[view] = controller
}
}
private fun handleAospTaskbarTouch(view: View, event: MotionEvent): Boolean? {
val buttonId = aospTaskbarButtonIds[view] ?: return null
val controller = aospTaskbarControllers[view] ?: return null
val config = getButtonConfig(buttonId)
if (config.longPressAction == NavButtonAction.STOCK) {
return null
}
when (event.actionMasked) {
MotionEvent.ACTION_DOWN -> {
aospTaskbarLongPressTriggered[view] = false
if (buttonId == NavButtonId.BACK) {
aospTaskbarBackLongPressTriggered[controller] = false
}
scheduleAospTaskbarLongPress(view, controller, buttonId, config)
}
MotionEvent.ACTION_UP,
MotionEvent.ACTION_CANCEL,
-> {
val triggered = aospTaskbarLongPressTriggered[view] == true
cancelAospTaskbarLongPress(view)
aospTaskbarLongPressTriggered.remove(view)
if (event.actionMasked == MotionEvent.ACTION_CANCEL && buttonId == NavButtonId.BACK) {
aospTaskbarBackLongPressTriggered.remove(controller)
}
if (triggered) {
return true
}
}
}
return null
}
private fun scheduleAospTaskbarLongPress(
view: View,
controller: Any,
buttonId: NavButtonId,
config: NavButtonConfig,
) {
cancelAospTaskbarLongPress(view)
val longPressRunnable = Runnable {
aospTaskbarLongPressTriggered[view] = true
if (buttonId == NavButtonId.BACK) {
aospTaskbarBackLongPressTriggered[controller] = true
}
updateContextFromTaskbar(controller, view)
view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS)
if (buttonId == NavButtonId.HOME) {
performAospTaskbarHomeLongPressAction(controller, config.longPressAction)
} else {
performAospTaskbarAction(controller, config.longPressAction)
}
}
aospTaskbarLongPressRunnables[view] = longPressRunnable
view.postDelayed(longPressRunnable, config.longPressDurationMs.toLong())
}
private fun cancelAospTaskbarLongPress(view: View) {
aospTaskbarLongPressRunnables.remove(view)?.let(view::removeCallbacks)
}
private fun hookHoneyspaceTaskbar(classLoader: ClassLoader?): Boolean { private fun hookHoneyspaceTaskbar(classLoader: ClassLoader?): Boolean {
val navButtonClass = findClassIfExists(HONEYSPACE_NAV_BUTTON_VIEW, classLoader) ?: run { val navButtonClass = findClassIfExists(HONEYSPACE_NAV_BUTTON_VIEW, classLoader) ?: run {
log("Launcher class not found: $HONEYSPACE_NAV_BUTTON_VIEW") log("Launcher class not found: $HONEYSPACE_NAV_BUTTON_VIEW")
@@ -937,6 +1215,14 @@ class NavButtons : XposedModule() {
context = currentContext.applicationContext ?: currentContext context = currentContext.applicationContext ?: currentContext
} }
private fun updateContextFromTaskbar(controller: Any?, view: Any?) {
if (view is View) {
updateContextFromView(view)
return
}
updateContextFromField(controller, "mContext")
}
private fun updateContextFromField(target: Any?, fieldName: String) { private fun updateContextFromField(target: Any?, fieldName: String) {
val currentContext = getFieldValue(target, fieldName) as? Context ?: return val currentContext = getFieldValue(target, fieldName) as? Context ?: return
context = currentContext.applicationContext ?: currentContext context = currentContext.applicationContext ?: currentContext
@@ -958,6 +1244,70 @@ class NavButtons : XposedModule() {
} }
} }
private fun performAospTaskbarHomeLongPressAction(controller: Any?, action: NavButtonAction) {
if (wasHomeLongPressHandledRecently()) {
return
}
noteHomeLongPressHandled()
performAospTaskbarAction(controller, action)
}
private fun performAospTaskbarAction(controller: Any?, action: NavButtonAction) {
when (action) {
NavButtonAction.STOCK,
NavButtonAction.NONE,
-> Unit
NavButtonAction.BACK -> {
if (!callAospTaskbarMethod(controller, "executeBack", arrayOf(KeyEvent::class.java), null)) {
performConfiguredAction(action)
}
}
NavButtonAction.HOME -> {
if (!callAospTaskbarMethod(controller, "navigateHome", emptyArray())) {
performConfiguredAction(action)
}
}
NavButtonAction.ASSISTANT -> {
if (!callAospTaskbarMethod(controller, "onLongPressHome", emptyArray())) {
performConfiguredAction(action)
}
}
NavButtonAction.RECENTS -> {
if (!callAospTaskbarMethod(controller, "navigateToOverview", emptyArray())) {
performConfiguredAction(action)
}
}
NavButtonAction.KILL_FOREGROUND_APP -> requestPrivilegedAction(PRIVILEGED_ACTION_KILL_FOREGROUND_APP)
NavButtonAction.TOGGLE_FLASHLIGHT -> requestPrivilegedAction(PRIVILEGED_ACTION_TOGGLE_FLASHLIGHT)
NavButtonAction.TOGGLE_AUTO_ROTATE -> performConfiguredAction(action)
}
}
private fun callAospTaskbarMethod(
controller: Any?,
methodName: String,
parameterTypes: Array<Class<*>>,
vararg args: Any?,
): Boolean {
if (controller == null) {
return false
}
return try {
callMethod(controller, methodName, parameterTypes, *args)
true
} catch (error: Throwable) {
log("AOSP taskbar $methodName failed: ${error.javaClass.simpleName}")
false
}
}
private fun sendKeyPress(keyCode: Int) { private fun sendKeyPress(keyCode: Int) {
try { try {
val inputManager = callStaticMethod( val inputManager = callStaticMethod(
@@ -1316,6 +1666,9 @@ class NavButtons : XposedModule() {
return return
} }
val currentContext = context ?: return val currentContext = context ?: return
if (currentContext.packageName == ANDROID_PACKAGE) {
return
}
val receiver = object : BroadcastReceiver() { val receiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) { override fun onReceive(context: Context?, intent: Intent?) {
@@ -1343,6 +1696,115 @@ class NavButtons : XposedModule() {
} }
} }
private fun registerPrivilegedActionReceiver() {
if (privilegedActionReceiverRegistered) {
return
}
val currentContext = context ?: getCurrentApplication() ?: return
context = currentContext.applicationContext ?: currentContext
val receiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
if (intent?.action != ACTION_PRIVILEGED_ACTION ||
context == null ||
!isAllowedPrivilegedActionSender(
context,
intent,
getSentFromPackageCompat(),
getSentFromUidCompat(),
)
) {
return
}
this@NavButtons.context = context.applicationContext ?: context
when (intent.getStringExtra(EXTRA_PRIVILEGED_ACTION)) {
PRIVILEGED_ACTION_KILL_FOREGROUND_APP -> killForegroundApp()
PRIVILEGED_ACTION_TOGGLE_FLASHLIGHT -> toggleFlashlight()
}
}
}
try {
currentContext.registerReceiver(
receiver,
IntentFilter(ACTION_PRIVILEGED_ACTION),
Context.RECEIVER_EXPORTED,
)
privilegedActionToken = readPrivilegedActionToken()
privilegedActionReceiverRegistered = true
} catch (error: Throwable) {
log("Privileged action receiver failed", error)
}
}
private fun BroadcastReceiver.getSentFromUidCompat(): Int {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
sentFromUid
} else {
Process.INVALID_UID
}
}
private fun BroadcastReceiver.getSentFromPackageCompat(): String? {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
sentFromPackage
} else {
null
}
}
private fun isAllowedPrivilegedActionSender(
context: Context,
intent: Intent,
senderPackage: String?,
senderUid: Int,
): Boolean {
if (senderPackage == AOSP_LAUNCHER_PACKAGE) {
return true
}
val expectedToken = privilegedActionToken ?: readPrivilegedActionToken()?.also {
privilegedActionToken = it
}
if (expectedToken != null &&
expectedToken == intent.getStringExtra(EXTRA_PRIVILEGED_ACTION_TOKEN)
) {
return true
}
if (senderUid == Process.SYSTEM_UID) {
return true
}
return context.packageManager.getPackagesForUid(senderUid)
?.contains(AOSP_LAUNCHER_PACKAGE) == true
}
private fun readPrivilegedActionToken(): String? {
return remotePreferences?.getString(NavButtonSettingsStore.KEY_PRIVILEGED_ACTION_TOKEN, null)
}
private fun requestPrivilegedAction(action: String) {
val currentContext = context
if (currentContext == null) {
when (action) {
PRIVILEGED_ACTION_KILL_FOREGROUND_APP -> killForegroundApp()
PRIVILEGED_ACTION_TOGGLE_FLASHLIGHT -> toggleFlashlight()
}
return
}
val token = remotePreferences?.getString(
NavButtonSettingsStore.KEY_PRIVILEGED_ACTION_TOKEN,
null,
)
val intent = Intent(ACTION_PRIVILEGED_ACTION)
.setPackage(ANDROID_PACKAGE)
.putExtra(EXTRA_PRIVILEGED_ACTION, action)
if (token != null) {
intent.putExtra(EXTRA_PRIVILEGED_ACTION_TOKEN, token)
}
currentContext.sendBroadcast(intent)
}
private fun trackSamsungNavigationBarView(startView: Any) { private fun trackSamsungNavigationBarView(startView: Any) {
var current: View? = startView as? View ?: return var current: View? = startView as? View ?: return
repeat(SAMSUNG_NAV_VIEW_PARENT_DEPTH) { repeat(SAMSUNG_NAV_VIEW_PARENT_DEPTH) {
@@ -1766,6 +2228,15 @@ class NavButtons : XposedModule() {
} }
} }
private fun buttonIdForAospTaskbarCode(buttonCode: Int?): NavButtonId? {
return when (buttonCode) {
AOSP_TASKBAR_BACK_BUTTON -> NavButtonId.BACK
AOSP_TASKBAR_HOME_BUTTON -> NavButtonId.HOME
AOSP_TASKBAR_RECENTS_BUTTON -> NavButtonId.RECENTS
else -> null
}
}
private fun getPackageNameFromComponent(component: Any?): String? { private fun getPackageNameFromComponent(component: Any?): String? {
return (component as? ComponentName)?.packageName return (component as? ComponentName)?.packageName
} }
@@ -1785,6 +2256,7 @@ class NavButtons : XposedModule() {
return packageName == null || return packageName == null ||
packageName == SYSTEMUI_PACKAGE || packageName == SYSTEMUI_PACKAGE ||
packageName == SAMSUNG_LAUNCHER_PACKAGE || packageName == SAMSUNG_LAUNCHER_PACKAGE ||
packageName == AOSP_LAUNCHER_PACKAGE ||
packageName == defaultLauncher packageName == defaultLauncher
} }
@@ -2316,6 +2788,7 @@ class NavButtons : XposedModule() {
const val STOCK_LONG_PRESS_GUARD_EARLY_MS = 75 const val STOCK_LONG_PRESS_GUARD_EARLY_MS = 75
const val STOCK_LONG_PRESS_GUARD_MIN_DELAY_MS = 100 const val STOCK_LONG_PRESS_GUARD_MIN_DELAY_MS = 100
const val SYSTEMUI_PACKAGE = "com.android.systemui" const val SYSTEMUI_PACKAGE = "com.android.systemui"
const val ANDROID_PACKAGE = "android"
const val SYSTEM_SERVER_PHONE_WINDOW_MANAGER = "com.android.server.policy.PhoneWindowManager" const val SYSTEM_SERVER_PHONE_WINDOW_MANAGER = "com.android.server.policy.PhoneWindowManager"
const val SYSTEMUI_KEY_BUTTON_VIEW = const val SYSTEMUI_KEY_BUTTON_VIEW =
"com.android.systemui.navigationbar.views.buttons.KeyButtonView" "com.android.systemui.navigationbar.views.buttons.KeyButtonView"
@@ -2326,6 +2799,20 @@ class NavButtons : XposedModule() {
const val SAMSUNG_NAVIGATION_BAR_VIEW = const val SAMSUNG_NAVIGATION_BAR_VIEW =
"com.android.systemui.navigationbar.views.SamsungNavigationBarView" "com.android.systemui.navigationbar.views.SamsungNavigationBarView"
const val SAMSUNG_LAUNCHER_PACKAGE = "com.sec.android.app.launcher" const val SAMSUNG_LAUNCHER_PACKAGE = "com.sec.android.app.launcher"
const val AOSP_LAUNCHER_PACKAGE = "com.android.launcher3"
const val AOSP_TASKBAR_NAV_BUTTON_CONTROLLER =
"com.android.launcher3.taskbar.TaskbarNavButtonController"
const val AOSP_TASKBAR_BACK_BUTTON = 1
const val AOSP_TASKBAR_HOME_BUTTON = 2
const val AOSP_TASKBAR_RECENTS_BUTTON = 4
const val AOSP_NAVBAR_BUTTONS_VIEW_CONTROLLER =
"com.android.launcher3.taskbar.NavbarButtonsViewController"
const val ACTION_PRIVILEGED_ACTION =
"se.ajpanton.navbuttons.action.PRIVILEGED_ACTION"
const val EXTRA_PRIVILEGED_ACTION = "privileged_action"
const val EXTRA_PRIVILEGED_ACTION_TOKEN = "privileged_action_token"
const val PRIVILEGED_ACTION_KILL_FOREGROUND_APP = "kill_foreground_app"
const val PRIVILEGED_ACTION_TOGGLE_FLASHLIGHT = "toggle_flashlight"
const val SIDE_ARROW_ICON_DP = 32f const val SIDE_ARROW_ICON_DP = 32f
const val SIDE_ARROW_GLYPH_SCALE = 0.8f const val SIDE_ARROW_GLYPH_SCALE = 0.8f
const val SIDE_ARROW_STROKE_WIDTH = 1.45f const val SIDE_ARROW_STROKE_WIDTH = 1.45f
@@ -1,4 +1,6 @@
android android
system
com.android.systemui com.android.systemui
com.android.launcher3
com.sec.android.app.launcher com.sec.android.app.launcher
com.samsung.systemui.navillera com.samsung.systemui.navillera