fix: remove OneUI unlocked icon cap
This commit is contained in:
+65
-1
@@ -4,6 +4,8 @@ import android.os.Handler
|
|||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
import android.service.notification.StatusBarNotification
|
import android.service.notification.StatusBarNotification
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
import io.github.libxposed.api.XposedInterface
|
import io.github.libxposed.api.XposedInterface
|
||||||
import se.ajpanton.notificationsmaster.visibility.NotificationSurface
|
import se.ajpanton.notificationsmaster.visibility.NotificationSurface
|
||||||
import java.lang.reflect.Method
|
import java.lang.reflect.Method
|
||||||
@@ -14,7 +16,9 @@ import java.util.function.Function
|
|||||||
/** Filters only OneUI's native unlocked status-bar container. */
|
/** Filters only OneUI's native unlocked status-bar container. */
|
||||||
internal class OneUiUnlockedIconBackend(private val framework: XposedInterface) : VisibilitySurfaceBackend {
|
internal class OneUiUnlockedIconBackend(private val framework: XposedInterface) : VisibilitySurfaceBackend {
|
||||||
private val controllers = Collections.newSetFromMap(WeakHashMap<Any, Boolean>())
|
private val controllers = Collections.newSetFromMap(WeakHashMap<Any, Boolean>())
|
||||||
|
private val iconContainers = Collections.newSetFromMap(WeakHashMap<View, Boolean>())
|
||||||
private lateinit var updateStatusBarIcons: Method
|
private lateinit var updateStatusBarIcons: Method
|
||||||
|
private lateinit var maxStaticIcons: java.lang.reflect.Field
|
||||||
@Volatile private var blockedObserved = false
|
@Volatile private var blockedObserved = false
|
||||||
|
|
||||||
override fun install(classLoader: ClassLoader): Boolean = runCatching {
|
override fun install(classLoader: ClassLoader): Boolean = runCatching {
|
||||||
@@ -25,6 +29,10 @@ internal class OneUiUnlockedIconBackend(private val framework: XposedInterface)
|
|||||||
require(it.type == container)
|
require(it.type == container)
|
||||||
it.isAccessible = true
|
it.isAccessible = true
|
||||||
}
|
}
|
||||||
|
maxStaticIcons = container.getDeclaredField("mMaxStaticIcons").also {
|
||||||
|
require(it.type == Int::class.javaPrimitiveType)
|
||||||
|
it.isAccessible = true
|
||||||
|
}
|
||||||
val sbn = entry.getDeclaredField("mSbn").also {
|
val sbn = entry.getDeclaredField("mSbn").also {
|
||||||
require(it.type == StatusBarNotification::class.java)
|
require(it.type == StatusBarNotification::class.java)
|
||||||
it.isAccessible = true
|
it.isAccessible = true
|
||||||
@@ -50,10 +58,13 @@ internal class OneUiUnlockedIconBackend(private val framework: XposedInterface)
|
|||||||
updateStatusBarIcons.isAccessible = true
|
updateStatusBarIcons.isAccessible = true
|
||||||
framework.hook(updateStatusBarIcons).intercept { chain ->
|
framework.hook(updateStatusBarIcons).intercept { chain ->
|
||||||
synchronized(controllers) { controllers += chain.thisObject }
|
synchronized(controllers) { controllers += chain.thisObject }
|
||||||
|
(notificationIcons.get(chain.thisObject) as? View)?.let(::manage)
|
||||||
chain.proceed()
|
chain.proceed()
|
||||||
}
|
}
|
||||||
framework.hook(update).intercept { chain ->
|
framework.hook(update).intercept { chain ->
|
||||||
if (chain.args[1] !== notificationIcons.get(chain.thisObject)) return@intercept chain.proceed()
|
val icons = notificationIcons.get(chain.thisObject)
|
||||||
|
if (chain.args[1] !== icons) return@intercept chain.proceed()
|
||||||
|
(icons as? View)?.let(::manage)
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
val original = chain.args[0] as? Function<Any, Any?> ?: return@intercept chain.proceed()
|
val original = chain.args[0] as? Function<Any, Any?> ?: return@intercept chain.proceed()
|
||||||
val wrapped = Function<Any, Any?> { item ->
|
val wrapped = Function<Any, Any?> { item ->
|
||||||
@@ -77,6 +88,28 @@ internal class OneUiUnlockedIconBackend(private val framework: XposedInterface)
|
|||||||
args[0] = wrapped
|
args[0] = wrapped
|
||||||
chain.proceed(args)
|
chain.proceed(args)
|
||||||
}
|
}
|
||||||
|
container.declaredMethods.filter { it.name == "calculateIconXTranslations" }.forEach { method ->
|
||||||
|
method.isAccessible = true
|
||||||
|
framework.hook(method).intercept { chain ->
|
||||||
|
(chain.thisObject as? View)?.takeIf(::isManaged)?.let(::applyLimit)
|
||||||
|
chain.proceed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
container.declaredMethods.filter { it.name == "shouldForceOverflow" }.forEach { method ->
|
||||||
|
method.isAccessible = true
|
||||||
|
framework.hook(method).intercept { chain ->
|
||||||
|
val view = chain.thisObject as? View
|
||||||
|
if (view == null || !isManaged(view) || chain.args.size < 4) {
|
||||||
|
return@intercept chain.proceed()
|
||||||
|
}
|
||||||
|
val limit = unlockedLimit()
|
||||||
|
applyLimit(view)
|
||||||
|
val index = chain.args[0] as? Int ?: return@intercept chain.proceed()
|
||||||
|
val speedBump = chain.args[1] as? Int ?: -1
|
||||||
|
val appear = chain.args[2] as? Float ?: 0f
|
||||||
|
(speedBump != -1 && index >= speedBump && appear > 0f) || index >= limit
|
||||||
|
}
|
||||||
|
}
|
||||||
}.onSuccess {
|
}.onSuccess {
|
||||||
Log.i(TAG, "Installed OneUI unlocked notification-icon backend")
|
Log.i(TAG, "Installed OneUI unlocked notification-icon backend")
|
||||||
}.onFailure {
|
}.onFailure {
|
||||||
@@ -94,10 +127,41 @@ internal class OneUiUnlockedIconBackend(private val framework: XposedInterface)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun manage(view: View) {
|
||||||
|
synchronized(iconContainers) { iconContainers += view }
|
||||||
|
applyLimit(view)
|
||||||
|
widenParent(view)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isManaged(view: View) = synchronized(iconContainers) { view in iconContainers }
|
||||||
|
|
||||||
|
private fun applyLimit(view: View) {
|
||||||
|
maxStaticIcons.setInt(view, unlockedLimit())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun unlockedLimit() = ProcessVisibilityPolicyCache.unlockedIconLimit ?: UNLIMITED_ICONS
|
||||||
|
|
||||||
|
private fun widenParent(view: View) {
|
||||||
|
var parent = view.parent as? View
|
||||||
|
repeat(3) {
|
||||||
|
val current = parent ?: return
|
||||||
|
if (current.javaClass.name.contains("AlphaOptimized")) {
|
||||||
|
current.layoutParams?.takeIf {
|
||||||
|
it.width == ViewGroup.LayoutParams.WRAP_CONTENT || it.width == 0
|
||||||
|
}?.let {
|
||||||
|
it.width = ViewGroup.LayoutParams.MATCH_PARENT
|
||||||
|
current.layoutParams = it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parent = current.parent as? View
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private companion object {
|
private companion object {
|
||||||
const val TAG = "NotificationsMaster"
|
const val TAG = "NotificationsMaster"
|
||||||
const val CONTROLLER = "com.android.systemui.statusbar.phone.LegacyNotificationIconAreaControllerImpl"
|
const val CONTROLLER = "com.android.systemui.statusbar.phone.LegacyNotificationIconAreaControllerImpl"
|
||||||
const val ICON_CONTAINER = "com.android.systemui.statusbar.phone.NotificationIconContainer"
|
const val ICON_CONTAINER = "com.android.systemui.statusbar.phone.NotificationIconContainer"
|
||||||
const val NOTIFICATION_ENTRY = "com.android.systemui.statusbar.notification.collection.NotificationEntry"
|
const val NOTIFICATION_ENTRY = "com.android.systemui.statusbar.notification.collection.NotificationEntry"
|
||||||
|
const val UNLIMITED_ICONS = 1000
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user