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.content.Context
20 import android.view.View
21 import android.view.View.GONE
22 import android.view.ViewGroup
23 import com.android.internal.widget.CachingIconView
24 import com.android.internal.widget.ConversationLayout
25 import com.android.internal.widget.MessagingLinearLayout
26 import com.android.systemui.R
27 import com.android.systemui.statusbar.TransformableView
28 import com.android.systemui.statusbar.ViewTransformationHelper
29 import com.android.systemui.statusbar.notification.NotificationUtils
30 import com.android.systemui.statusbar.notification.TransformState
31 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
32 import com.android.systemui.statusbar.notification.row.HybridNotificationView
33 
34 /**
35  * Wraps a notification containing a conversation template
36  */
37 class NotificationConversationTemplateViewWrapper constructor(
38     ctx: Context,
39     view: View,
40     row: ExpandableNotificationRow
41 ) : NotificationTemplateViewWrapper(ctx, view, row) {
42 
43     private val minHeightWithActions: Int = NotificationUtils.getFontScaledHeight(
44             ctx,
45             R.dimen.notification_messaging_actions_min_height
46     )
47     private val conversationLayout: ConversationLayout = view as ConversationLayout
48 
49     private lateinit var conversationIconView: CachingIconView
50     private lateinit var conversationBadgeBg: View
51     private lateinit var expandButton: View
52     private lateinit var expandButtonContainer: View
53     private lateinit var expandButtonInnerContainer: View
54     private lateinit var imageMessageContainer: ViewGroup
55     private lateinit var messagingLinearLayout: MessagingLinearLayout
56     private lateinit var conversationTitleView: View
57     private lateinit var importanceRing: View
58     private lateinit var appName: View
59     private var facePileBottomBg: View? = null
60     private var facePileBottom: View? = null
61     private var facePileTop: View? = null
62 
63     private fun resolveViews() {
64         messagingLinearLayout = conversationLayout.messagingLinearLayout
65         imageMessageContainer = conversationLayout.imageMessageContainer
66         with(conversationLayout) {
67             conversationIconView = requireViewById(com.android.internal.R.id.conversation_icon)
68             conversationBadgeBg =
69                     requireViewById(com.android.internal.R.id.conversation_icon_badge_bg)
70             expandButton = requireViewById(com.android.internal.R.id.expand_button)
71             expandButtonContainer =
72                     requireViewById(com.android.internal.R.id.expand_button_container)
73             expandButtonInnerContainer =
74                     requireViewById(com.android.internal.R.id.expand_button_inner_container)
75             importanceRing = requireViewById(com.android.internal.R.id.conversation_icon_badge_ring)
76             appName = requireViewById(com.android.internal.R.id.app_name_text)
77             conversationTitleView = requireViewById(com.android.internal.R.id.conversation_text)
78             facePileTop = findViewById(com.android.internal.R.id.conversation_face_pile_top)
79             facePileBottom = findViewById(com.android.internal.R.id.conversation_face_pile_bottom)
80             facePileBottomBg =
81                     findViewById(com.android.internal.R.id.conversation_face_pile_bottom_background)
82         }
83     }
84 
85     override fun onContentUpdated(row: ExpandableNotificationRow) {
86         // Reinspect the notification. Before the super call, because the super call also updates
87         // the transformation types and we need to have our values set by then.
88         resolveViews()
89         super.onContentUpdated(row)
90     }
91 
92     override fun updateTransformedTypes() {
93         // This also clears the existing types
94         super.updateTransformedTypes()
95 
96         addTransformedViews(
97                 messagingLinearLayout,
98                 appName,
99                 conversationTitleView)
100 
101         // Let's ignore the image message container since that is transforming as part of the
102         // messages already
103         mTransformationHelper.setCustomTransformation(
104                 object : ViewTransformationHelper.CustomTransformation() {
105                     override fun transformTo(
106                         ownState: TransformState,
107                         otherView: TransformableView,
108                         transformationAmount: Float
109                     ): Boolean {
110                         if (otherView is HybridNotificationView) {
111                             return false
112                         }
113                         // we're hidden by default by the transformState
114                         ownState.ensureVisible()
115                         // Let's do nothing otherwise, this is already handled by the messages
116                         return true
117                     }
118 
119                     override fun transformFrom(
120                         ownState: TransformState,
121                         otherView: TransformableView,
122                         transformationAmount: Float
123                     ): Boolean =
124                             transformTo(ownState, otherView, transformationAmount)
125                 },
126                 imageMessageContainer.id
127         )
128 
129         addViewsTransformingToSimilar(
130                 conversationIconView,
131                 conversationBadgeBg,
132                 expandButton,
133                 importanceRing,
134                 facePileTop,
135                 facePileBottom,
136                 facePileBottomBg
137         )
138     }
139 
140     override fun getExpandButton() = expandButtonInnerContainer
141 
142     override fun setShelfIconVisible(visible: Boolean) {
143         if (conversationLayout.isImportantConversation) {
144             if (conversationIconView.visibility != GONE) {
145                 conversationIconView.isForceHidden = visible
146                 // We don't want the small icon to be hidden by the extended wrapper, as force
147                 // hiding the conversationIcon will already do that via its listener.
148                 return
149             }
150         }
151         super.setShelfIconVisible(visible)
152     }
153 
154     override fun getShelfTransformationTarget(): View? =
155             if (conversationLayout.isImportantConversation)
156                 if (conversationIconView.visibility != GONE)
157                     conversationIconView
158                 else
159                     // A notification with a fallback icon was set to important. Currently
160                     // the transformation doesn't work for these and needs to be fixed.
161                     // In the meantime those are using the icon.
162                     super.getShelfTransformationTarget()
163             else
164                 super.getShelfTransformationTarget()
165 
166     override fun setRemoteInputVisible(visible: Boolean) =
167             conversationLayout.showHistoricMessages(visible)
168 
169     override fun updateExpandability(expandable: Boolean, onClickListener: View.OnClickListener?) =
170             conversationLayout.updateExpandability(expandable, onClickListener)
171 
172     override fun disallowSingleClick(x: Float, y: Float): Boolean {
173         val isOnExpandButton = expandButtonContainer.visibility == View.VISIBLE &&
174                 isOnView(expandButtonContainer, x, y)
175         return isOnExpandButton || super.disallowSingleClick(x, y)
176     }
177 
178     override fun getMinLayoutHeight(): Int =
179             if (mActionsContainer != null && mActionsContainer.visibility != View.GONE)
180                 minHeightWithActions
181             else
182                 super.getMinLayoutHeight()
183 
184     private fun addTransformedViews(vararg vs: View?) =
185             vs.forEach { view -> view?.let(mTransformationHelper::addTransformedView) }
186 
187     private fun addViewsTransformingToSimilar(vararg vs: View?) =
188             vs.forEach { view -> view?.let(mTransformationHelper::addViewTransformingToSimilar) }
189 }
190