Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 19128d77 authored by Ned Burns's avatar Ned Burns Committed by Android (Google) Code Review
Browse files

Merge "Spin off node generation logic into testable class" into sc-v2-dev

parents 16699a13 b6732216
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -78,7 +78,7 @@ fun treeSpecToStr(tree: NodeSpec): String {
}

private fun treeSpecToStrHelper(tree: NodeSpec, sb: StringBuilder, indent: String) {
    sb.append("${indent}ns{${tree.controller.nodeLabel}")
    sb.append("${indent}{${tree.controller.nodeLabel}}\n")
    if (tree.children.isNotEmpty()) {
        val childIndent = "$indent  "
        for (child in tree.children) {
+73 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.statusbar.notification.collection.render

import com.android.systemui.statusbar.notification.collection.GroupEntry
import com.android.systemui.statusbar.notification.collection.ListEntry
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.listbuilder.NotifSection

/**
 * Converts a notif list (the output of the ShadeListBuilder) into a NodeSpec, an abstract
 * representation of which views should be present in the shade. This spec will later be consumed
 * by the ViewDiffer, which will add and remove views until the shade matches the spec. Up until
 * this point, the pipeline has dealt with pure data representations of notifications (in the
 * form of NotificationEntries). In this step, NotificationEntries finally become associated with
 * the views that will represent them. In addition, we add in any non-notification views that also
 * need to present in the shade, notably the section headers.
 */
class NodeSpecBuilder(
    private val viewBarn: NotifViewBarn
) {
    fun buildNodeSpec(
        rootController: NodeController,
        notifList: List<ListEntry>
    ): NodeSpec {
        val root = NodeSpecImpl(null, rootController)
        var currentSection: NotifSection? = null
        val prevSections = mutableSetOf<NotifSection?>()

        for (entry in notifList) {
            val section = entry.section!!

            if (prevSections.contains(section)) {
                throw java.lang.RuntimeException("Section ${section.label} has been duplicated")
            }

            // If this notif begins a new section, first add the section's header view
            if (section != currentSection) {
                section.headerController?.let { headerController ->
                    root.children.add(NodeSpecImpl(root, headerController))
                }
                prevSections.add(currentSection)
                currentSection = section
            }

            // Finally, add the actual notif node!
            root.children.add(buildNotifNode(root, entry))
        }

        return root
    }

    private fun buildNotifNode(parent: NodeSpec, entry: ListEntry): NodeSpec = when (entry) {
        is NotificationEntry -> NodeSpecImpl(parent, viewBarn.requireView(entry))
        is GroupEntry -> NodeSpecImpl(parent, viewBarn.requireView(checkNotNull(entry.summary)))
                .apply { entry.children.forEach { children.add(buildNotifNode(this, it)) } }
        else -> throw RuntimeException("Unexpected entry: $entry")
    }
}
+4 −6
Original line number Diff line number Diff line
@@ -19,18 +19,16 @@ package com.android.systemui.statusbar.notification.collection.render
import android.view.textclassifier.Log
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.statusbar.notification.collection.ListEntry
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRowController
import javax.inject.Inject

/**
 * The ViewBarn is just a map from [ListEntry] to an instance of an
 * [ExpandableNotificationRowController].
 * The ViewBarn is just a map from [ListEntry] to an instance of a [NodeController].
 */
@SysUISingleton
class NotifViewBarn @Inject constructor() {
    private val rowMap = mutableMapOf<String, ExpandableNotificationRowController>()
    private val rowMap = mutableMapOf<String, NodeController>()

    fun requireView(forEntry: ListEntry): ExpandableNotificationRowController {
    fun requireView(forEntry: ListEntry): NodeController {
        if (DEBUG) {
            Log.d(TAG, "requireView: $forEntry.key")
        }
@@ -42,7 +40,7 @@ class NotifViewBarn @Inject constructor() {
        return li
    }

    fun registerViewForEntry(entry: ListEntry, controller: ExpandableNotificationRowController) {
    fun registerViewForEntry(entry: ListEntry, controller: NodeController) {
        if (DEBUG) {
            Log.d(TAG, "registerViewForEntry: $entry.key")
        }
+4 −30
Original line number Diff line number Diff line
@@ -18,9 +18,7 @@ package com.android.systemui.statusbar.notification.collection.render

import android.content.Context
import android.view.View
import com.android.systemui.statusbar.notification.collection.GroupEntry
import com.android.systemui.statusbar.notification.collection.ListEntry
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.ShadeListBuilder
import com.android.systemui.statusbar.notification.stack.NotificationListContainer
import com.android.systemui.statusbar.phone.NotificationIconAreaController
@@ -34,45 +32,21 @@ class ShadeViewManager constructor(
    context: Context,
    listContainer: NotificationListContainer,
    logger: ShadeViewDifferLogger,
    private val viewBarn: NotifViewBarn,
    viewBarn: NotifViewBarn,
    private val notificationIconAreaController: NotificationIconAreaController
) {
    // We pass a shim view here because the listContainer may not actually have a view associated
    // with it and the differ never actually cares about the root node's view.
    private val rootController = RootNodeController(listContainer, View(context))
    private val specBuilder = NodeSpecBuilder(viewBarn)
    private val viewDiffer = ShadeViewDiffer(rootController, logger)

    fun attach(listBuilder: ShadeListBuilder) =
            listBuilder.setOnRenderListListener(::onNewNotifTree)

    private fun onNewNotifTree(tree: List<ListEntry>) = viewDiffer.applySpec(buildTree(tree))

    private fun buildTree(notifList: List<ListEntry>): NodeSpec {
        val root = NodeSpecImpl(null, rootController).apply {
            // Insert first section header, if present
            notifList.firstOrNull()?.section?.headerController?.let {
                children.add(NodeSpecImpl(this, it))
            }
            notifList.firstOrNull()?.let {
                children.add(buildNotifNode(it, this))
            }
            notifList.asSequence().zipWithNext().forEach { (prev, entry) ->
                // Insert new header if the section has changed between two entries
                entry.section.takeIf { it != prev.section }?.headerController?.let {
                    children.add(NodeSpecImpl(this, it))
                }
                children.add(buildNotifNode(entry, this))
            }
        }
    private fun onNewNotifTree(notifList: List<ListEntry>) {
        viewDiffer.applySpec(specBuilder.buildNodeSpec(rootController, notifList))
        notificationIconAreaController.updateNotificationIcons(notifList)
        return root
    }

    private fun buildNotifNode(entry: ListEntry, parent: NodeSpec): NodeSpec = when (entry) {
        is NotificationEntry -> NodeSpecImpl(parent, viewBarn.requireView(entry))
        is GroupEntry -> NodeSpecImpl(parent, viewBarn.requireView(checkNotNull(entry.summary)))
                .apply { entry.children.forEach { children.add(buildNotifNode(it, this)) } }
        else -> throw RuntimeException("Unexpected entry: $entry")
    }
}

+4 −0
Original line number Diff line number Diff line
@@ -30,3 +30,7 @@ inline fun modifyEntry(
    modifier(builder)
    builder.apply(entry)
}

fun getAttachState(entry: ListEntry): ListAttachState {
    return entry.attachState
}
Loading