fix: refresh OneUI lockscreen battery indication

This commit is contained in:
ajp_anton
2026-08-30 23:31:30 +00:00
parent fe99f789ed
commit 55de8f7aa9
@@ -40,7 +40,10 @@ internal class OneUiMiscBackend(private val framework: XposedInterface) : Visibi
return installed > 0 return installed > 0
} }
override fun onPolicyChanged() = aodBattery.refresh() override fun onPolicyChanged() {
lockscreenBattery.refresh()
aodBattery.refresh()
}
private companion object { const val TAG = "NotificationsMaster" } private companion object { const val TAG = "NotificationsMaster" }
} }
@@ -128,39 +131,81 @@ private class AodCallVisibilityController(private val framework: XposedInterface
} }
private class LockscreenBatteryController(private val framework: XposedInterface) { private class LockscreenBatteryController(private val framework: XposedInterface) {
private var controller: Any? = null
private var batteryEvent: Any? = null
private var restingEvent: Any? = null
private lateinit var addTimeout: Method
private lateinit var addResting: Method
private lateinit var remove: Method
private var failed = false private var failed = false
fun install(classLoader: ClassLoader): Boolean { fun install(classLoader: ClassLoader): Boolean = runCatching {
val eventClass = classLoader.findClass("com.android.systemui.statusbar.IndicationEventType") ?: return false val eventClass = requireNotNull(classLoader.findClass("com.android.systemui.statusbar.IndicationEventType"))
val batteryEvent = eventClass.staticField("BATTERY") ?: return false batteryEvent = requireNotNull(eventClass.staticField("BATTERY"))
val restingEvent = eventClass.staticField("BATTERY_RESTING") ?: return false restingEvent = requireNotNull(eventClass.staticField("BATTERY_RESTING"))
val controller = classLoader.findClass( val controllerClass = requireNotNull(
"com.android.systemui.statusbar.KeyguardSecIndicationController", classLoader.findClass("com.android.systemui.statusbar.KeyguardSecIndicationController"),
) ?: return false )
val methods = controller.methodsNamed("addInitialIndication") addTimeout = controllerClass.getDeclaredMethod(
methods.forEach { method -> "addIndicationTimeout",
eventClass,
CharSequence::class.java,
ColorStateList::class.java,
Boolean::class.javaPrimitiveType,
).also { it.isAccessible = true }
addResting = controllerClass.getDeclaredMethod(
"addIndication",
eventClass,
CharSequence::class.java,
).also { it.isAccessible = true }
remove = controllerClass.getDeclaredMethod("removeIndication", eventClass).also { it.isAccessible = true }
val method = controllerClass.getDeclaredMethod("addInitialIndication").also { it.isAccessible = true }
framework.intercept(method) { chain -> framework.intercept(method) { chain ->
val result = chain.proceed() val result = chain.proceed()
runCatching { controller = chain.thisObject
val target = chain.thisObject update(chain.thisObject)
val context = target.field("mContext") as? Context ?: return@runCatching result
val state = visibleLockscreenBattery(context, target) ?: return@runCatching }
val text = state.formattedPercent() classLoader.findClass("com.android.systemui.statusbar.KeyguardIndicationController\$4")
val color = target.field("mInitialTextColorState") as? ColorStateList ?.getDeclaredMethod("onDozingChanged", Boolean::class.javaPrimitiveType)
target.invokeNamed("addIndicationTimeout", batteryEvent, text, color, false) ?.also { it.isAccessible = true }
target.invokeNamed("addIndication", restingEvent, text) ?.let { dozingChanged ->
}.onFailure(::logFailureOnce) framework.intercept(dozingChanged) { chain ->
val result = chain.proceed()
val target = chain.thisObject.field("this\$0")
if (chain.args.firstOrNull() == false && controllerClass.isInstance(target)) {
controller = target
update(target)
}
result result
} }
} }
return methods.isNotEmpty() }.onFailure { error ->
Log.w(TAG, "OneUI lockscreen battery boundary is unavailable", error)
}.isSuccess
fun refresh() {
val target = controller ?: return
(target.field("mIndicationArea") as? View)?.post { update(target) } ?: update(target)
} }
private fun visibleLockscreenBattery(context: Context, controller: Any): BatteryState? { private fun update(target: Any?) = runCatching {
if (!ProcessVisibilityPolicyCache.systemUiMisc.showLockscreenBatteryPercentWhenUnplugged) return null if (target.field("mDozing") == true) return@runCatching
if (controller.field("mDozing") == true) return null val context = target.field("mContext") as? Context ?: return@runCatching
return currentBatteryState(context)?.takeUnless { it.plugged || it.charged } val state = currentBatteryState(context) ?: return@runCatching
if (state.plugged || state.charged) return@runCatching
val battery = batteryEvent ?: return@runCatching
val resting = restingEvent ?: return@runCatching
if (!ProcessVisibilityPolicyCache.systemUiMisc.showLockscreenBatteryPercentWhenUnplugged) {
remove.invoke(target, battery)
remove.invoke(target, resting)
return@runCatching
} }
val text = state.formattedPercent()
val color = target.field("mInitialTextColorState") as? ColorStateList
addTimeout.invoke(target, battery, text, color, false)
addResting.invoke(target, resting, text)
}.onFailure(::logFailureOnce)
private fun logFailureOnce(error: Throwable) { private fun logFailureOnce(error: Throwable) {
if (failed) return if (failed) return