Fix stale View tracking in ShadeViewDiffer

NSSL can independently re-inflate certain Views (such as section
headers) which will cause the View references tracked by ShadeViewDiffer
to become stale. This results in odd behavior when SVD compares its
tracked Views with the ones in NSSL.

The tracking serves as an optimization, so rather than maintain the
additional state across pipeline runes, we re-generate the View->Spec
lookup map once per run.

Fixes: 216150338
Test: 1. Have silent notifications in the shade
      2. Change the device theme.
      3. Dismiss all notifications 1 by 1
      4. Verify Silent Header is no longer visible once no more silent
         notifications are present.
Change-Id: I1e500e2868b6c4825dd6f7cc7e2d8cf61b831773
This commit is contained in:
Steve Elliott
2022-03-17 16:36:53 -04:00
parent 40ca086c40
commit 0b0791615e

View File

@@ -18,7 +18,6 @@ package com.android.systemui.statusbar.notification.collection.render
import android.annotation.MainThread
import android.view.View
import com.android.systemui.util.kotlin.transform
import com.android.systemui.util.traceSection
/**
@@ -41,7 +40,6 @@ class ShadeViewDiffer(
) {
private val rootNode = ShadeNode(rootController)
private val nodes = mutableMapOf(rootController to rootNode)
private val views = mutableMapOf<View, ShadeNode>()
/**
* Adds and removes views from the root (and its children) until their structure matches the
@@ -66,26 +64,25 @@ class ShadeViewDiffer(
*
* For debugging purposes.
*/
fun getViewLabel(view: View): String = views[view]?.label ?: view.toString()
fun getViewLabel(view: View): String =
nodes.values.firstOrNull { node -> node.view === view }?.label ?: view.toString()
private fun detachChildren(
parentNode: ShadeNode,
specMap: Map<NodeController, NodeSpec>
) {
val parentSpec = specMap[parentNode.controller]
for (i in parentNode.getChildCount() - 1 downTo 0) {
val childView = parentNode.getChildAt(i)
views[childView]?.let { childNode ->
val childSpec = specMap[childNode.controller]
maybeDetachChild(parentNode, parentSpec, childNode, childSpec)
if (childNode.controller.getChildCount() > 0) {
detachChildren(childNode, specMap)
private fun detachChildren(parentNode: ShadeNode, specMap: Map<NodeController, NodeSpec>) {
val views = nodes.values.asSequence().map { node -> node.view to node }.toMap()
fun detachRecursively(parentNode: ShadeNode, specMap: Map<NodeController, NodeSpec>) {
val parentSpec = specMap[parentNode.controller]
for (i in parentNode.getChildCount() - 1 downTo 0) {
val childView = parentNode.getChildAt(i)
views[childView]?.let { childNode ->
val childSpec = specMap[childNode.controller]
maybeDetachChild(parentNode, parentSpec, childNode, childSpec)
if (childNode.controller.getChildCount() > 0) {
detachRecursively(childNode, specMap)
}
}
}
}
detachRecursively(parentNode, specMap)
}
private fun maybeDetachChild(
@@ -94,14 +91,13 @@ class ShadeViewDiffer(
childNode: ShadeNode,
childSpec: NodeSpec?
) {
val newParentNode = transform(childSpec?.parent) { getNode(it) }
val newParentNode = childSpec?.parent?.let { getNode(it) }
if (newParentNode != parentNode) {
val childCompletelyRemoved = newParentNode == null
if (childCompletelyRemoved) {
nodes.remove(childNode.controller)
views.remove(childNode.controller.view)
}
logger.logDetachingChild(
@@ -115,10 +111,7 @@ class ShadeViewDiffer(
}
}
private fun attachChildren(
parentNode: ShadeNode,
specMap: Map<NodeController, NodeSpec>
) {
private fun attachChildren(parentNode: ShadeNode, specMap: Map<NodeController, NodeSpec>) {
val parentSpec = checkNotNull(specMap[parentNode.controller])
for ((index, childSpec) in parentSpec.children.withIndex()) {
@@ -160,7 +153,6 @@ class ShadeViewDiffer(
if (node == null) {
node = ShadeNode(spec.controller)
nodes[node.controller] = node
views[node.view] = node
}
return node
}
@@ -194,10 +186,9 @@ class ShadeViewDiffer(
private class DuplicateNodeException(message: String) : RuntimeException(message)
private class ShadeNode(
val controller: NodeController
) {
val view = controller.view
private class ShadeNode(val controller: NodeController) {
val view: View
get() = controller.view
var parent: ShadeNode? = null