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.row.wrapper 18 19 import android.app.Flags 20 import android.app.Flags.notificationsRedesignTemplates 21 import android.content.Context 22 import android.graphics.drawable.AnimatedImageDrawable 23 import android.view.View 24 import android.view.ViewGroup 25 import androidx.core.view.isVisible 26 import com.android.internal.widget.CachingIconView 27 import com.android.internal.widget.ConversationLayout 28 import com.android.internal.widget.MessagingGroup 29 import com.android.internal.widget.MessagingImageMessage 30 import com.android.internal.widget.MessagingLinearLayout 31 import com.android.internal.widget.NotificationRowIconView 32 import com.android.systemui.res.R 33 import com.android.systemui.statusbar.notification.NotificationFadeAware 34 import com.android.systemui.statusbar.notification.NotificationUtils 35 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow 36 import com.android.systemui.statusbar.notification.row.wrapper.NotificationMessagingTemplateViewWrapper.setCustomImageMessageTransform 37 import com.android.systemui.util.children 38 39 /** Wraps a notification containing a conversation template */ 40 class NotificationConversationTemplateViewWrapper( 41 ctx: Context, 42 view: View, 43 row: ExpandableNotificationRow, 44 ) : NotificationTemplateViewWrapper(ctx, view, row) { 45 46 private val minHeightWithActions: Int = 47 NotificationUtils.getFontScaledHeight( 48 ctx, 49 R.dimen.notification_messaging_actions_min_height, 50 ) 51 private val conversationLayout: ConversationLayout = view as ConversationLayout 52 53 private lateinit var conversationIconContainer: View 54 private lateinit var conversationIconView: CachingIconView 55 private lateinit var badgeIconView: NotificationRowIconView 56 private lateinit var conversationBadgeBg: View 57 private lateinit var expandBtn: View 58 private var expandBtnContainer: View? = null 59 private var imageMessageContainer: ViewGroup? = null 60 private lateinit var messageContainers: ArrayList<MessagingGroup> 61 private lateinit var messagingLinearLayout: MessagingLinearLayout 62 private lateinit var conversationTitleView: View 63 private lateinit var importanceRing: View 64 private lateinit var appName: View 65 private var facePileBottomBg: View? = null 66 private var facePileBottom: View? = null 67 private var facePileTop: View? = null 68 69 private fun resolveViews() { 70 messagingLinearLayout = conversationLayout.messagingLinearLayout 71 imageMessageContainer = conversationLayout.imageMessageContainer 72 messageContainers = conversationLayout.messagingGroups 73 with(conversationLayout) { 74 conversationIconContainer = 75 requireViewById(com.android.internal.R.id.conversation_icon_container) 76 conversationIconView = requireViewById(com.android.internal.R.id.conversation_icon) 77 if (Flags.notificationsRedesignAppIcons()) { 78 badgeIconView = requireViewById(com.android.internal.R.id.icon) 79 } 80 conversationBadgeBg = 81 requireViewById(com.android.internal.R.id.conversation_icon_badge_bg) 82 expandBtn = requireViewById(com.android.internal.R.id.expand_button) 83 expandBtnContainer = findViewById(com.android.internal.R.id.expand_button_container) 84 importanceRing = requireViewById(com.android.internal.R.id.conversation_icon_badge_ring) 85 appName = requireViewById(com.android.internal.R.id.app_name_text) 86 conversationTitleView = 87 requireViewById( 88 if (notificationsRedesignTemplates()) com.android.internal.R.id.title 89 else com.android.internal.R.id.conversation_text 90 ) 91 facePileTop = findViewById(com.android.internal.R.id.conversation_face_pile_top) 92 facePileBottom = findViewById(com.android.internal.R.id.conversation_face_pile_bottom) 93 facePileBottomBg = 94 findViewById(com.android.internal.R.id.conversation_face_pile_bottom_background) 95 } 96 } 97 98 override fun onContentUpdated(row: ExpandableNotificationRow) { 99 // Reinspect the notification. Before the super call, because the super call also updates 100 // the transformation types and we need to have our values set by then. 101 resolveViews() 102 super.onContentUpdated(row) 103 } 104 105 override fun updateTransformedTypes() { 106 // This also clears the existing types 107 super.updateTransformedTypes() 108 109 mTransformationHelper.addTransformedView(TRANSFORMING_VIEW_TITLE, conversationTitleView) 110 addTransformedViews(messagingLinearLayout, appName) 111 112 setCustomImageMessageTransform(mTransformationHelper, imageMessageContainer) 113 114 addViewsTransformingToSimilar( 115 conversationIconView, 116 conversationBadgeBg, 117 expandBtn, 118 importanceRing, 119 facePileTop, 120 facePileBottom, 121 facePileBottomBg, 122 ) 123 } 124 125 override fun getShelfTransformationTarget(): View? = 126 if (conversationLayout.isImportantConversation) 127 if (conversationIconView.visibility != View.GONE) conversationIconView 128 else 129 // A notification with a fallback icon was set to important. Currently 130 // the transformation doesn't work for these and needs to be fixed. 131 // In the meantime those are using the icon. 132 super.getShelfTransformationTarget() 133 else super.getShelfTransformationTarget() 134 135 override fun setRemoteInputVisible(visible: Boolean) = 136 conversationLayout.showHistoricMessages(visible) 137 138 override fun updateExpandability( 139 expandable: Boolean, 140 onClickListener: View.OnClickListener, 141 requestLayout: Boolean, 142 ) { 143 if (notificationsRedesignTemplates()) { 144 super.updateExpandability(expandable, onClickListener, requestLayout) 145 } else { 146 conversationLayout.updateExpandability(expandable, onClickListener) 147 } 148 } 149 150 override fun disallowSingleClick(x: Float, y: Float): Boolean { 151 val isOnExpandButton = 152 if (notificationsRedesignTemplates()) { 153 expandBtn.isVisible && isOnView(expandBtn, x, y) 154 } else { 155 expandBtnContainer?.visibility == View.VISIBLE && isOnView(expandBtnContainer, x, y) 156 } 157 return isOnExpandButton || super.disallowSingleClick(x, y) 158 } 159 160 override fun getMinLayoutHeight(): Int = 161 if (mActionsContainer != null && mActionsContainer.visibility != View.GONE) 162 minHeightWithActions 163 else super.getMinLayoutHeight() 164 165 override fun setNotificationFaded(faded: Boolean) { 166 // Do not call super 167 NotificationFadeAware.setLayerTypeForFaded(expandBtn, faded) 168 NotificationFadeAware.setLayerTypeForFaded(conversationIconContainer, faded) 169 } 170 171 // Starts or stops the animations in any drawables contained in this Conversation Notification. 172 override fun setAnimationsRunning(running: Boolean) { 173 // We apply to both the child message containers in a conversation group, 174 // and the top level image message container. 175 val containers = 176 messageContainers.asSequence().map { it.messageContainer } + 177 if (notificationsRedesignTemplates() && imageMessageContainer == null) 178 emptySequence() 179 else sequenceOf(imageMessageContainer!!) 180 val drawables = 181 containers 182 .flatMap { it.children } 183 .mapNotNull { child -> 184 (child as? MessagingImageMessage)?.let { imageMessage -> 185 imageMessage.drawable as? AnimatedImageDrawable 186 } 187 } 188 drawables.toSet().forEach { 189 when { 190 running -> it.start() 191 !running -> it.stop() 192 } 193 } 194 } 195 } 196