diff --git a/app/src/main/java/se/ajpanton/notificationsmaster/module/NotificationsMasterModule.kt b/app/src/main/java/se/ajpanton/notificationsmaster/module/NotificationsMasterModule.kt index 7911ae5..1aad498 100644 --- a/app/src/main/java/se/ajpanton/notificationsmaster/module/NotificationsMasterModule.kt +++ b/app/src/main/java/se/ajpanton/notificationsmaster/module/NotificationsMasterModule.kt @@ -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) diff --git a/app/src/main/java/se/ajpanton/notificationsmaster/module/SamsungAodBackend.kt b/app/src/main/java/se/ajpanton/notificationsmaster/module/SamsungAodBackend.kt index b8f864f..4403ff9 100644 --- a/app/src/main/java/se/ajpanton/notificationsmaster/module/SamsungAodBackend.kt +++ b/app/src/main/java/se/ajpanton/notificationsmaster/module/SamsungAodBackend.kt @@ -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) diff --git a/app/src/main/java/se/ajpanton/notificationsmaster/module/SamsungAodPluginBackend.kt b/app/src/main/java/se/ajpanton/notificationsmaster/module/SamsungAodPluginBackend.kt new file mode 100644 index 0000000..f07a5a0 --- /dev/null +++ b/app/src/main/java/se/ajpanton/notificationsmaster/module/SamsungAodPluginBackend.kt @@ -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()) + private val backends = mutableListOf() + + 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" + } +}