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
}
override fun onPolicyChanged() = aodBattery.refresh()
override fun onPolicyChanged() {
lockscreenBattery.refresh()
aodBattery.refresh()
}
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 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
fun install(classLoader: ClassLoader): Boolean {
val eventClass = classLoader.findClass("com.android.systemui.statusbar.IndicationEventType") ?: return false
val batteryEvent = eventClass.staticField("BATTERY") ?: return false
val restingEvent = eventClass.staticField("BATTERY_RESTING") ?: return false
val controller = classLoader.findClass(
"com.android.systemui.statusbar.KeyguardSecIndicationController",
) ?: return false
val methods = controller.methodsNamed("addInitialIndication")
methods.forEach { method ->
fun install(classLoader: ClassLoader): Boolean = runCatching {
val eventClass = requireNotNull(classLoader.findClass("com.android.systemui.statusbar.IndicationEventType"))
batteryEvent = requireNotNull(eventClass.staticField("BATTERY"))
restingEvent = requireNotNull(eventClass.staticField("BATTERY_RESTING"))
val controllerClass = requireNotNull(
classLoader.findClass("com.android.systemui.statusbar.KeyguardSecIndicationController"),
)
addTimeout = controllerClass.getDeclaredMethod(
"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 ->
val result = chain.proceed()
runCatching {
val target = chain.thisObject
val context = target.field("mContext") as? Context ?: return@runCatching
val state = visibleLockscreenBattery(context, target) ?: return@runCatching
val text = state.formattedPercent()
val color = target.field("mInitialTextColorState") as? ColorStateList
target.invokeNamed("addIndicationTimeout", batteryEvent, text, color, false)
target.invokeNamed("addIndication", restingEvent, text)
}.onFailure(::logFailureOnce)
controller = chain.thisObject
update(chain.thisObject)
result
}
classLoader.findClass("com.android.systemui.statusbar.KeyguardIndicationController\$4")
?.getDeclaredMethod("onDozingChanged", Boolean::class.javaPrimitiveType)
?.also { it.isAccessible = true }
?.let { dozingChanged ->
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
}
}
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? {
if (!ProcessVisibilityPolicyCache.systemUiMisc.showLockscreenBatteryPercentWhenUnplugged) return null
if (controller.field("mDozing") == true) return null
return currentBatteryState(context)?.takeUnless { it.plugged || it.charged }
private fun update(target: Any?) = runCatching {
if (target.field("mDozing") == true) return@runCatching
val context = target.field("mContext") as? Context ?: return@runCatching
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) {
if (failed) return