Fix OneUI lockscreen card overflow filtering
This commit is contained in:
+76
-2
@@ -20,6 +20,13 @@ internal class OneUiLockscreenCardsBackend(
|
||||
private val hiddenRows = WeakHashMap<View, RowState>()
|
||||
private lateinit var entryForRow: (View) -> Any?
|
||||
private lateinit var sbnForEntry: (Any) -> StatusBarNotification?
|
||||
private lateinit var shelfNotification: Field
|
||||
private lateinit var shelfIconStates: Field
|
||||
private lateinit var shelfClampedAmount: Field
|
||||
private lateinit var shelfAppearAmount: Field
|
||||
private lateinit var shelfAlpha: Field
|
||||
private lateinit var shelfHidden: Field
|
||||
private lateinit var shelfVisibleState: Field
|
||||
@Volatile private var statusBarStateKnown = false
|
||||
@Volatile private var statusBarState = SHADE
|
||||
@Volatile private var dozing = false
|
||||
@@ -31,6 +38,7 @@ internal class OneUiLockscreenCardsBackend(
|
||||
val rowClass = Class.forName(ROW, false, classLoader)
|
||||
val stateController = Class.forName(STATE_CONTROLLER, false, classLoader)
|
||||
prepareNotificationAccess(rowClass)
|
||||
installShelfFilter(classLoader)
|
||||
|
||||
stackClass.declaredMethods.filter { it.name == "onViewAdded" }.forEach { method ->
|
||||
method.isAccessible = true
|
||||
@@ -103,6 +111,43 @@ internal class OneUiLockscreenCardsBackend(
|
||||
sbnForEntry = { accessor(it) as? StatusBarNotification }
|
||||
}
|
||||
|
||||
private fun installShelfFilter(classLoader: ClassLoader) {
|
||||
val shelfIcons = Class.forName(SHELF_ICONS, false, classLoader)
|
||||
val iconView = Class.forName(STATUS_BAR_ICON_VIEW, false, classLoader)
|
||||
shelfNotification = iconView.getDeclaredField("mNotification").also {
|
||||
require(it.type == StatusBarNotification::class.java)
|
||||
it.isAccessible = true
|
||||
}
|
||||
shelfIconStates = findField(shelfIcons, "mIconStates")
|
||||
?: error("OneUI shelf icon states are unavailable")
|
||||
val iconState = Class.forName(ICON_STATE, false, classLoader)
|
||||
shelfClampedAmount = requireField(iconState, "clampedAppearAmount")
|
||||
shelfAppearAmount = requireField(iconState, "iconAppearAmount")
|
||||
shelfAlpha = requireField(iconState, "mAlpha")
|
||||
shelfHidden = requireField(iconState, "hidden")
|
||||
shelfVisibleState = requireField(iconState, "visibleState")
|
||||
val calculate = shelfIcons.declaredMethods.singleOrNull {
|
||||
it.name == "calculateIconXTranslations" && it.parameterCount == 0
|
||||
} ?: error("OneUI shelf icon layout method not found")
|
||||
calculate.isAccessible = true
|
||||
framework.hook(calculate).intercept { chain ->
|
||||
val container = chain.thisObject as? ViewGroup ?: return@intercept chain.proceed()
|
||||
if (!isLockscreenCards(container)) return@intercept chain.proceed()
|
||||
val children = List(container.childCount, container::getChildAt)
|
||||
val blocked = children.filter(::isBlockedShelfIcon)
|
||||
if (blocked.isEmpty()) return@intercept chain.proceed()
|
||||
val states = shelfIconStates.get(container) as? Map<*, *>
|
||||
?: return@intercept chain.proceed()
|
||||
blocked.forEach { icon -> states[icon]?.let(::hideShelfIconState) }
|
||||
children.filterNot(blocked::contains).forEach(container::bringChildToFront)
|
||||
try {
|
||||
chain.proceed()
|
||||
} finally {
|
||||
children.forEach(container::bringChildToFront)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun accessor(method: Method?, field: Field?): (Any) -> Any? {
|
||||
method?.isAccessible = true
|
||||
field?.isAccessible = true
|
||||
@@ -123,7 +168,7 @@ internal class OneUiLockscreenCardsBackend(
|
||||
}
|
||||
|
||||
private fun applyStack(stack: ViewGroup) {
|
||||
val active = statusBarStateKnown && statusBarState == KEYGUARD && !dozing && isCardsMode(stack)
|
||||
val active = isLockscreenCards(stack)
|
||||
repeat(stack.childCount) { index ->
|
||||
val row = stack.getChildAt(index)
|
||||
if (row.javaClass.name == ROW) {
|
||||
@@ -134,16 +179,30 @@ internal class OneUiLockscreenCardsBackend(
|
||||
|
||||
private fun applyRow(row: View) {
|
||||
val stack = row.parent as? ViewGroup ?: return
|
||||
val active = statusBarStateKnown && statusBarState == KEYGUARD && !dozing && isCardsMode(stack)
|
||||
val active = isLockscreenCards(stack)
|
||||
if (active && isBlocked(row)) hideRow(row) else restoreRow(row)
|
||||
}
|
||||
|
||||
private fun isLockscreenCards(view: View) =
|
||||
statusBarStateKnown && statusBarState == KEYGUARD && !dozing && isCardsMode(view)
|
||||
|
||||
private fun isCardsMode(view: View) = runCatching {
|
||||
Settings.System.getInt(view.context.contentResolver, LOCKSCREEN_STYLE) == CARDS
|
||||
}.getOrDefault(false)
|
||||
|
||||
private fun isBlocked(row: View): Boolean {
|
||||
val sbn = runCatching { entryForRow(row)?.let(sbnForEntry) }.getOrNull() ?: return false
|
||||
return isBlocked(sbn)
|
||||
}
|
||||
|
||||
private fun isBlockedShelfIcon(icon: View): Boolean {
|
||||
if (icon.javaClass.name != STATUS_BAR_ICON_VIEW) return false
|
||||
val sbn = runCatching { shelfNotification.get(icon) as? StatusBarNotification }.getOrNull()
|
||||
?: return false
|
||||
return isBlocked(sbn)
|
||||
}
|
||||
|
||||
private fun isBlocked(sbn: StatusBarNotification): Boolean {
|
||||
return ProcessVisibilityPolicyCache.isBlocked(
|
||||
VisibilityNotificationExtractor.from(sbn),
|
||||
NotificationSurface.LOCKSCREEN_COLLAPSED,
|
||||
@@ -155,6 +214,14 @@ internal class OneUiLockscreenCardsBackend(
|
||||
}
|
||||
}
|
||||
|
||||
private fun hideShelfIconState(state: Any) {
|
||||
shelfClampedAmount.setFloat(state, 0f)
|
||||
shelfAppearAmount.setFloat(state, 0f)
|
||||
shelfAlpha.setFloat(state, 0f)
|
||||
shelfHidden.setBoolean(state, true)
|
||||
shelfVisibleState.setInt(state, ICON_HIDDEN)
|
||||
}
|
||||
|
||||
private fun hideRow(row: View) {
|
||||
if (row.visibility == View.GONE && row.alpha == 0f) return
|
||||
hiddenRows.putIfAbsent(row, RowState(row.visibility, row.alpha))
|
||||
@@ -183,6 +250,9 @@ internal class OneUiLockscreenCardsBackend(
|
||||
}
|
||||
}
|
||||
|
||||
private fun requireField(type: Class<*>, name: String) =
|
||||
findField(type, name) ?: error("OneUI $name field is unavailable")
|
||||
|
||||
private fun findField(type: Class<*>, vararg names: String): Field? {
|
||||
var current: Class<*>? = type
|
||||
while (current != null) {
|
||||
@@ -204,10 +274,14 @@ internal class OneUiLockscreenCardsBackend(
|
||||
const val SHADE = 0
|
||||
const val KEYGUARD = 1
|
||||
const val CARDS = 0
|
||||
const val ICON_HIDDEN = 2
|
||||
const val LOCKSCREEN_STYLE = "lockscreen_minimizing_notification"
|
||||
const val STACK = "com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout"
|
||||
const val ROW = "com.android.systemui.statusbar.notification.row.ExpandableNotificationRow"
|
||||
const val STATE_CONTROLLER = "com.android.systemui.statusbar.StatusBarStateControllerImpl"
|
||||
const val SHELF_ICONS = "com.android.systemui.statusbar.phone.SecShelfNotificationIconContainer"
|
||||
const val STATUS_BAR_ICON_VIEW = "com.android.systemui.statusbar.StatusBarIconView"
|
||||
const val ICON_STATE = "com.android.systemui.statusbar.phone.NotificationIconContainer\$IconState"
|
||||
const val ONE_UI_LOCKSCREEN_COORDINATOR =
|
||||
"com.android.systemui.statusbar.notification.collection.coordinator.LockScreenNotiIconCoordinator"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user