• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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