Improve AOSP side arrow support
This commit is contained in:
@@ -94,6 +94,7 @@ class NavButtons : XposedModule() {
|
||||
private var samsungNavigationBarViewHookInstalled = false
|
||||
private var aospSystemUiSideArrowHookInstalled = false
|
||||
private var aospTaskbarTintHookInstalled = false
|
||||
private var aospSystemUiDarkIntensity = 0f
|
||||
private var settingsChangedReceiverRegistered = false
|
||||
private var privilegedActionReceiverRegistered = false
|
||||
private var privilegedActionToken: String? = null
|
||||
@@ -543,14 +544,14 @@ class NavButtons : XposedModule() {
|
||||
|
||||
private fun hookAospSystemUiSideArrows(classLoader: ClassLoader?, keyButtonClass: Class<*>) {
|
||||
if (aospSystemUiSideArrowHookInstalled ||
|
||||
Build.MANUFACTURER.equals("samsung", ignoreCase = true) ||
|
||||
Build.VERSION.SDK_INT < 35
|
||||
Build.MANUFACTURER.equals("samsung", ignoreCase = true)
|
||||
) {
|
||||
return
|
||||
}
|
||||
val inflaterClass = findFirstClassIfExists(AOSP_NAVIGATION_BAR_INFLATER_VIEW_CLASSES, classLoader) ?: return
|
||||
aospSystemUiSideArrowHookInstalled = true
|
||||
registerSettingsChangedReceiver()
|
||||
hookAospSystemUiDarkIntensity(classLoader)
|
||||
|
||||
findMethodIfExists(inflaterClass, "getDefaultLayout")?.let { method ->
|
||||
deoptimizeMethodIfPresent(method)
|
||||
@@ -572,14 +573,14 @@ class NavButtons : XposedModule() {
|
||||
chain.thisObject?.let(::trackAospSystemUiInflater)
|
||||
val layout = chain.args.getOrNull(0) as? String
|
||||
if (layout != null) {
|
||||
chain.args[0] = if (isSideArrowsEnabled()) {
|
||||
val updatedLayout = if (isSideArrowsEnabled()) {
|
||||
addAospSystemUiSideArrows(layout)
|
||||
} else {
|
||||
removeAospSystemUiSideArrows(layout)
|
||||
}
|
||||
runCatching { chain.args[0] = updatedLayout }
|
||||
}
|
||||
val result = chain.proceed()
|
||||
result
|
||||
chain.proceed()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -605,17 +606,6 @@ class NavButtons : XposedModule() {
|
||||
}
|
||||
}
|
||||
|
||||
findMethodIfExists(keyButtonClass, "setImageDrawable", Drawable::class.java)?.let { method ->
|
||||
deoptimizeMethodIfPresent(method)
|
||||
hook(method).intercept { chain ->
|
||||
aospSystemUiSideArrowDirections[chain.thisObject]?.let { direction ->
|
||||
createAospSystemUiSideArrowDrawable(chain.thisObject, direction)?.let { drawable ->
|
||||
chain.args[0] = drawable
|
||||
}
|
||||
}
|
||||
chain.proceed()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun trackAospSystemUiInflater(inflater: Any) {
|
||||
@@ -762,6 +752,34 @@ class NavButtons : XposedModule() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun hookAospSystemUiDarkIntensity(classLoader: ClassLoader?) {
|
||||
val transitionsClass = findFirstClassIfExists(
|
||||
AOSP_NAVIGATION_BAR_TRANSITIONS_CLASSES,
|
||||
classLoader,
|
||||
) ?: return
|
||||
findMethodIfExists(
|
||||
transitionsClass,
|
||||
"applyDarkIntensity",
|
||||
Float::class.javaPrimitiveType!!,
|
||||
)?.let { method ->
|
||||
deoptimizeMethodIfPresent(method)
|
||||
hook(method).intercept { chain ->
|
||||
val result = chain.proceed()
|
||||
aospSystemUiDarkIntensity = (chain.args.getOrNull(0) as? Float)?.coerceIn(0f, 1f)
|
||||
?: aospSystemUiDarkIntensity
|
||||
updateAospSystemUiSideArrowDarkIntensity()
|
||||
result
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateAospSystemUiSideArrowDarkIntensity() {
|
||||
aospSystemUiSideArrowDirections.keys.toList().forEach { view ->
|
||||
callFloatMethodIfExists(view, "setDarkIntensity", aospSystemUiDarkIntensity)
|
||||
setFieldIfExists(view, "mDarkIntensity", aospSystemUiDarkIntensity)
|
||||
}
|
||||
}
|
||||
|
||||
private fun findAospSystemUiKeyButtons(view: View): List<ImageView> {
|
||||
val result = mutableListOf<ImageView>()
|
||||
if (view is ImageView && getFieldValue(view, "mCode") != null) {
|
||||
@@ -779,7 +797,10 @@ class NavButtons : XposedModule() {
|
||||
val view = value as? ImageView ?: return
|
||||
val direction = aospSystemUiSideArrowDirections[view] ?: return
|
||||
ensureContextFromView(view)
|
||||
createAospSystemUiSideArrowDrawable(view, direction)?.let(view::setImageDrawable)
|
||||
createAospSystemUiSideArrowDrawable(view, direction)?.let {
|
||||
view.setImageDrawable(it)
|
||||
callFloatMethodIfExists(view, "setDarkIntensity", aospSystemUiDarkIntensity)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createAospSystemUiSideArrowDrawable(
|
||||
@@ -798,17 +819,18 @@ class NavButtons : XposedModule() {
|
||||
Boolean::class.javaPrimitiveType,
|
||||
Boolean::class.javaPrimitiveType,
|
||||
)
|
||||
.apply { isAccessible = true }
|
||||
.newInstance(Color.WHITE, Color.rgb(55, 58, 62), false, false)
|
||||
keyButtonDrawableClass
|
||||
val drawable = keyButtonDrawableClass
|
||||
.getDeclaredConstructor(Drawable::class.java, stateClass)
|
||||
.apply { isAccessible = true }
|
||||
.newInstance(
|
||||
sideArrowBitmapDrawable(
|
||||
view.context,
|
||||
direction,
|
||||
Color.WHITE,
|
||||
),
|
||||
sideArrowBitmapDrawable(view.context, direction, Color.WHITE),
|
||||
state,
|
||||
) as? Drawable
|
||||
drawable?.also {
|
||||
callFloatMethodIfExists(it, "setDarkIntensity", aospSystemUiDarkIntensity)
|
||||
}
|
||||
} catch (error: Throwable) {
|
||||
log("AOSP SystemUI side arrow drawable failed: ${error.javaClass.simpleName}")
|
||||
null
|
||||
@@ -1113,7 +1135,7 @@ class NavButtons : XposedModule() {
|
||||
) {
|
||||
arrow.minimumWidth = home.minimumWidth
|
||||
arrow.minimumHeight = home.minimumHeight
|
||||
arrow.setPadding(0, home.paddingTop, 0, home.paddingBottom)
|
||||
arrow.setPadding(0, 0, 0, 0)
|
||||
arrow.scaleType = ImageView.ScaleType.CENTER
|
||||
arrow.setImageDrawable(sideArrowBitmapDrawable(arrow.context, direction, Color.WHITE))
|
||||
}
|
||||
@@ -1204,8 +1226,14 @@ class NavButtons : XposedModule() {
|
||||
}
|
||||
|
||||
private fun placeAospTaskbarArrow(arrow: View, center: Point) {
|
||||
arrow.x = center.x - arrow.width / 2f
|
||||
arrow.y = center.y - arrow.height / 2f
|
||||
val width = arrow.width.takeIf { it > 0 }
|
||||
?: arrow.layoutParams?.width?.takeIf { it > 0 }
|
||||
?: 0
|
||||
val height = arrow.height.takeIf { it > 0 }
|
||||
?: arrow.layoutParams?.height?.takeIf { it > 0 }
|
||||
?: 0
|
||||
arrow.x = center.x - width / 2f
|
||||
arrow.y = center.y - height / 2f
|
||||
}
|
||||
|
||||
private fun removeAospSideArrows(container: ViewGroup) {
|
||||
@@ -1901,9 +1929,23 @@ class NavButtons : XposedModule() {
|
||||
NavButtonAction.HOME -> sendKeyPress(KeyEvent.KEYCODE_HOME)
|
||||
NavButtonAction.ASSISTANT -> sendKeyPress(KeyEvent.KEYCODE_ASSIST)
|
||||
NavButtonAction.RECENTS -> sendKeyPress(KeyEvent.KEYCODE_APP_SWITCH)
|
||||
NavButtonAction.KILL_FOREGROUND_APP -> killForegroundApp()
|
||||
NavButtonAction.KILL_FOREGROUND_APP ->
|
||||
performPrivilegedActionOrDirect(PRIVILEGED_ACTION_KILL_FOREGROUND_APP)
|
||||
|
||||
NavButtonAction.TOGGLE_AUTO_ROTATE -> toggleAutoRotate()
|
||||
NavButtonAction.TOGGLE_FLASHLIGHT -> toggleFlashlight()
|
||||
NavButtonAction.TOGGLE_FLASHLIGHT ->
|
||||
performPrivilegedActionOrDirect(PRIVILEGED_ACTION_TOGGLE_FLASHLIGHT)
|
||||
}
|
||||
}
|
||||
|
||||
private fun performPrivilegedActionOrDirect(action: String) {
|
||||
if (context?.packageName == ANDROID_PACKAGE) {
|
||||
when (action) {
|
||||
PRIVILEGED_ACTION_KILL_FOREGROUND_APP -> killForegroundApp()
|
||||
PRIVILEGED_ACTION_TOGGLE_FLASHLIGHT -> toggleFlashlight()
|
||||
}
|
||||
} else {
|
||||
requestPrivilegedAction(action)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2837,7 +2879,10 @@ class NavButtons : XposedModule() {
|
||||
return resolveInfo?.activityInfo?.packageName
|
||||
}
|
||||
|
||||
private fun getTopPackageName(): String? = getTopPackageFromActivityTaskManager()
|
||||
private fun getTopPackageName(): String? {
|
||||
return getTopPackageFromActivityTaskManager()
|
||||
?: getTopPackageFromRunningTasks()
|
||||
}
|
||||
|
||||
private fun getTopPackageFromActivityTaskManager(): String? {
|
||||
return try {
|
||||
@@ -2862,6 +2907,21 @@ class NavButtons : XposedModule() {
|
||||
return pkg ?: getPackageNameFromActivityInfo(getFieldValue(taskInfo, "topActivityInfo"))
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
private fun getTopPackageFromRunningTasks(): String? {
|
||||
val activityManager = context?.getSystemService(Context.ACTIVITY_SERVICE) as? ActivityManager
|
||||
?: return null
|
||||
return try {
|
||||
activityManager.getRunningTasks(1)
|
||||
.firstOrNull()
|
||||
?.topActivity
|
||||
?.packageName
|
||||
} catch (error: Throwable) {
|
||||
log("ActivityManager.getRunningTasks failed: ${error.javaClass.simpleName}")
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private fun getFieldValue(target: Any?, fieldName: String): Any? {
|
||||
if (target == null) {
|
||||
return null
|
||||
@@ -3519,6 +3579,10 @@ class NavButtons : XposedModule() {
|
||||
"com.android.systemui.navigationbar.views.NavigationBarInflaterView",
|
||||
"com.android.systemui.navigationbar.NavigationBarInflaterView",
|
||||
)
|
||||
val AOSP_NAVIGATION_BAR_TRANSITIONS_CLASSES = listOf(
|
||||
"com.android.systemui.navigationbar.NavigationBarTransitions",
|
||||
"com.android.systemui.navigationbar.views.NavigationBarTransitions",
|
||||
)
|
||||
val AOSP_KEY_BUTTON_DRAWABLE_CLASSES = listOf(
|
||||
"com.android.systemui.navigationbar.views.buttons.KeyButtonDrawable",
|
||||
"com.android.systemui.navigationbar.buttons.KeyButtonDrawable",
|
||||
@@ -3527,8 +3591,8 @@ class NavButtons : XposedModule() {
|
||||
"com.android.systemui.navigationbar.views.buttons.KeyButtonDrawable\$ShadowDrawableState",
|
||||
"com.android.systemui.navigationbar.buttons.KeyButtonDrawable\$ShadowDrawableState",
|
||||
)
|
||||
const val AOSP_SYSUI_LEFT_ARROW_BUTTON = "key(21)"
|
||||
const val AOSP_SYSUI_RIGHT_ARROW_BUTTON = "key(22)"
|
||||
const val AOSP_SYSUI_LEFT_ARROW_BUTTON = "key(21:)"
|
||||
const val AOSP_SYSUI_RIGHT_ARROW_BUTTON = "key(22:)"
|
||||
const val ACTION_PRIVILEGED_ACTION =
|
||||
"se.ajpanton.navbuttons.action.PRIVILEGED_ACTION"
|
||||
const val EXTRA_PRIVILEGED_ACTION = "privileged_action"
|
||||
|
||||
Reference in New Issue
Block a user