Fix OneUI AOD Cards grid rendering

This commit is contained in:
ajp_anton
2026-08-29 23:47:25 +00:00
parent b7d6bb6d63
commit ce4adef117
3 changed files with 59 additions and 2 deletions
@@ -26,6 +26,7 @@ class NotificationsMasterModule : XposedModule() {
systemUiBackends = listOfNotNull(unlocked) + listOf(
OneUiLockscreenBackend(this),
OneUiLockscreenCardsBackend(this),
SamsungAodPluginBackend(this),
).filter { it.install(param.classLoader) }
ProcessVisibilityPolicyCache.installWhenReady {
systemUiBackends.orEmpty().forEach(VisibilitySurfaceBackend::onPolicyChanged)
@@ -1,5 +1,6 @@
package se.ajpanton.notificationsmaster.module
import android.graphics.drawable.Icon
import android.os.Handler
import android.os.Looper
import android.provider.Settings
@@ -103,6 +104,7 @@ internal class SamsungAodBackend(private val framework: XposedInterface) : Visib
framework.hook(method).intercept { chain ->
val result = chain.proceed()
(chain.thisObject as? ViewGroup)?.let { view ->
trackCardsContainer(view)
cardsDozing[view] = chain.args.firstOrNull() == true
refreshCardsGrid()
}
@@ -115,6 +117,7 @@ internal class SamsungAodBackend(private val framework: XposedInterface) : Visib
method.isAccessible = true
framework.hook(method).intercept { chain ->
val result = chain.proceed()
(chain.thisObject as? ViewGroup)?.let(::trackCardsContainer)
refreshCardsGrid()
result
}
@@ -155,12 +158,15 @@ internal class SamsungAodBackend(private val framework: XposedInterface) : Visib
container.javaClass.getMethod("getIconColor").invoke(container) as Int
}.getOrNull()
val sources = notifications.map { sbn ->
val icon = sbn.notification.smallIcon
OneUiCardsGridRenderer.Source(
sbn.key,
view = null,
sbn.notification.smallIcon,
icon,
sbn.packageName,
tint,
tint.takeUnless {
icon.type == Icon.TYPE_BITMAP || icon.type == Icon.TYPE_ADAPTIVE_BITMAP
},
)
}
cardsRenderer.updateSources(container, sources)
@@ -0,0 +1,50 @@
package se.ajpanton.notificationsmaster.module
import android.util.Log
import io.github.libxposed.api.XposedInterface
import java.util.Collections
import java.util.IdentityHashMap
/** Installs the Samsung AOD backend after SystemUI supplies its plugin class loader. */
internal class SamsungAodPluginBackend(private val framework: XposedInterface) : VisibilitySurfaceBackend {
private val classLoaders = Collections.newSetFromMap(IdentityHashMap<ClassLoader, Boolean>())
private val backends = mutableListOf<VisibilitySurfaceBackend>()
override fun install(classLoader: ClassLoader): Boolean = runCatching {
val manager = Class.forName(PLUGIN_MANAGER, false, classLoader)
val methods = manager.declaredMethods.filter { it.name == SET_PLUGIN }
require(methods.isNotEmpty()) { "$SET_PLUGIN is unavailable" }
methods.forEach { method ->
method.isAccessible = true
framework.hook(method).intercept { chain ->
val result = chain.proceed()
chain.args.firstOrNull()?.javaClass?.classLoader?.let(::installPlugin)
result
}
}
}.onSuccess {
Log.i(TAG, "Installed Samsung AOD plugin-loader backend")
}.onFailure { error ->
Log.d(TAG, "Samsung AOD plugin-loader boundary is unavailable", error)
}.isSuccess
override fun onPolicyChanged() {
synchronized(backends) { backends.toList() }.forEach(VisibilitySurfaceBackend::onPolicyChanged)
}
private fun installPlugin(classLoader: ClassLoader) {
synchronized(classLoaders) {
if (!classLoaders.add(classLoader)) return
}
SamsungAodBackend(framework).takeIf { it.install(classLoader) }?.let { backend ->
synchronized(backends) { backends += backend }
backend.onPolicyChanged()
}
}
private companion object {
const val TAG = "NotificationsMaster"
const val PLUGIN_MANAGER = "com.android.systemui.doze.PluginAODManager"
const val SET_PLUGIN = "setAODPlugin"
}
}