1 /* <lambda>null2 * Copyright (C) 2020 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 android.content.Context 20 import android.view.View 21 import com.android.systemui.statusbar.notification.collection.GroupEntry 22 import com.android.systemui.statusbar.notification.collection.ListEntry 23 import com.android.systemui.statusbar.notification.collection.NotificationEntry 24 import com.android.systemui.statusbar.notification.collection.ShadeListBuilder 25 import com.android.systemui.statusbar.notification.stack.NotificationListContainer 26 import com.android.systemui.statusbar.phone.NotificationIconAreaController 27 import javax.inject.Inject 28 29 /** 30 * Responsible for building and applying the "shade node spec": the list (tree) of things that 31 * currently populate the notification shade. 32 */ 33 class ShadeViewManager constructor( 34 context: Context, 35 listContainer: NotificationListContainer, 36 logger: ShadeViewDifferLogger, 37 private val viewBarn: NotifViewBarn, 38 private val notificationIconAreaController: NotificationIconAreaController 39 ) { 40 // We pass a shim view here because the listContainer may not actually have a view associated 41 // with it and the differ never actually cares about the root node's view. 42 private val rootController = RootNodeController(listContainer, View(context)) 43 private val viewDiffer = ShadeViewDiffer(rootController, logger) 44 45 fun attach(listBuilder: ShadeListBuilder) = 46 listBuilder.setOnRenderListListener(::onNewNotifTree) 47 48 private fun onNewNotifTree(tree: List<ListEntry>) = viewDiffer.applySpec(buildTree(tree)) 49 50 private fun buildTree(notifList: List<ListEntry>): NodeSpec { 51 val root = NodeSpecImpl(null, rootController).apply { 52 // Insert first section header, if present 53 notifList.firstOrNull()?.section?.headerController?.let { 54 children.add(NodeSpecImpl(this, it)) 55 } 56 notifList.asSequence().zipWithNext().forEach { (prev, entry) -> 57 // Insert new header if the section has changed between two entries 58 entry.section.takeIf { it != prev.section }?.headerController?.let { 59 children.add(NodeSpecImpl(this, it)) 60 } 61 children.add(buildNotifNode(entry, this)) 62 } 63 } 64 notificationIconAreaController.updateNotificationIcons(notifList) 65 return root 66 } 67 68 private fun buildNotifNode(entry: ListEntry, parent: NodeSpec): 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(it, this)) } } 72 else -> throw RuntimeException("Unexpected entry: $entry") 73 } 74 } 75 76 class ShadeViewManagerFactory @Inject constructor( 77 private val context: Context, 78 private val logger: ShadeViewDifferLogger, 79 private val viewBarn: NotifViewBarn, 80 private val notificationIconAreaController: NotificationIconAreaController 81 ) { createnull82 fun create(listContainer: NotificationListContainer) = 83 ShadeViewManager( 84 context, 85 listContainer, 86 logger, 87 viewBarn, 88 notificationIconAreaController) 89 } 90