1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.statusbar.notification.collection.render 18 19 import com.android.systemui.statusbar.notification.collection.GroupEntry 20 import com.android.systemui.statusbar.notification.collection.ListEntry 21 import com.android.systemui.statusbar.notification.collection.NotificationEntry 22 import com.android.systemui.statusbar.notification.collection.listbuilder.NotifSection 23 import com.android.systemui.util.traceSection 24 25 /** 26 * Converts a notif list (the output of the ShadeListBuilder) into a NodeSpec, an abstract 27 * representation of which views should be present in the shade. This spec will later be consumed 28 * by the ViewDiffer, which will add and remove views until the shade matches the spec. Up until 29 * this point, the pipeline has dealt with pure data representations of notifications (in the 30 * form of NotificationEntries). In this step, NotificationEntries finally become associated with 31 * the views that will represent them. In addition, we add in any non-notification views that also 32 * need to present in the shade, notably the section headers. 33 */ 34 class NodeSpecBuilder( 35 private val viewBarn: NotifViewBarn 36 ) { 37 fun buildNodeSpec( 38 rootController: NodeController, 39 notifList: List<ListEntry> 40 ): NodeSpec = traceSection("NodeSpecBuilder.buildNodeSpec") { 41 val root = NodeSpecImpl(null, rootController) 42 var currentSection: NotifSection? = null 43 val prevSections = mutableSetOf<NotifSection?>() 44 45 for (entry in notifList) { 46 val section = entry.section!! 47 48 if (prevSections.contains(section)) { 49 throw java.lang.RuntimeException("Section ${section.label} has been duplicated") 50 } 51 52 // If this notif begins a new section, first add the section's header view 53 if (section != currentSection) { 54 section.headerController?.let { headerController -> 55 root.children.add(NodeSpecImpl(root, headerController)) 56 } 57 prevSections.add(currentSection) 58 currentSection = section 59 } 60 61 // Finally, add the actual notif node! 62 root.children.add(buildNotifNode(root, entry)) 63 } 64 65 return root 66 } 67 68 private fun buildNotifNode(parent: NodeSpec, entry: ListEntry): NodeSpec = when (entry) { 69 is NotificationEntry -> NodeSpecImpl(parent, viewBarn.requireView(entry)) 70 is GroupEntry -> NodeSpecImpl(parent, viewBarn.requireView(checkNotNull(entry.summary))) 71 .apply { entry.children.forEach { children.add(buildNotifNode(this, it)) } } 72 else -> throw RuntimeException("Unexpected entry: $entry") 73 } 74 } 75