1 /*
2  * 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;
18 
19 import android.annotation.Nullable;
20 import android.content.Context;
21 import android.graphics.drawable.Icon;
22 import android.text.TextUtils;
23 import android.util.AttributeSet;
24 import android.view.View;
25 import android.widget.FrameLayout;
26 import android.widget.ImageView;
27 import android.widget.TextView;
28 
29 import com.android.internal.widget.ConversationLayout;
30 import com.android.systemui.R;
31 import com.android.systemui.statusbar.notification.NotificationFadeAware;
32 
33 /**
34  * A hybrid view which may contain information about one ore more conversations.
35  */
36 public class HybridConversationNotificationView extends HybridNotificationView {
37 
38     private ImageView mConversationIconView;
39     private TextView mConversationSenderName;
40     private View mConversationFacePile;
41     private int mSingleAvatarSize;
42     private int mFacePileSize;
43     private int mFacePileAvatarSize;
44     private int mFacePileProtectionWidth;
45 
HybridConversationNotificationView(Context context)46     public HybridConversationNotificationView(Context context) {
47         this(context, null);
48     }
49 
HybridConversationNotificationView(Context context, @Nullable AttributeSet attrs)50     public HybridConversationNotificationView(Context context, @Nullable AttributeSet attrs) {
51         this(context, attrs, 0);
52     }
53 
HybridConversationNotificationView( Context context, @Nullable AttributeSet attrs, int defStyleAttr)54     public HybridConversationNotificationView(
55             Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
56         this(context, attrs, defStyleAttr, 0);
57     }
58 
HybridConversationNotificationView( Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes)59     public HybridConversationNotificationView(
60             Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
61         super(context, attrs, defStyleAttr, defStyleRes);
62     }
63 
64     @Override
onFinishInflate()65     protected void onFinishInflate() {
66         super.onFinishInflate();
67         mConversationIconView = requireViewById(com.android.internal.R.id.conversation_icon);
68         mConversationFacePile = requireViewById(com.android.internal.R.id.conversation_face_pile);
69         mConversationSenderName = requireViewById(R.id.conversation_notification_sender);
70         applyTextColor(mConversationSenderName, mSecondaryTextColor);
71         mFacePileSize = getResources()
72                 .getDimensionPixelSize(R.dimen.conversation_single_line_face_pile_size);
73         mFacePileAvatarSize = getResources()
74                 .getDimensionPixelSize(R.dimen.conversation_single_line_face_pile_avatar_size);
75         mSingleAvatarSize = getResources()
76                 .getDimensionPixelSize(R.dimen.conversation_single_line_avatar_size);
77         mFacePileProtectionWidth = getResources().getDimensionPixelSize(
78                 R.dimen.conversation_single_line_face_pile_protection_width);
79         mTransformationHelper.setCustomTransformation(
80                 new FadeOutAndDownWithTitleTransformation(mConversationSenderName),
81                 mConversationSenderName.getId());
82         mTransformationHelper.addViewTransformingToSimilar(mConversationIconView);
83         mTransformationHelper.addTransformedView(mConversationSenderName);
84     }
85 
86     @Override
bind(@ullable CharSequence title, @Nullable CharSequence text, @Nullable View contentView)87     public void bind(@Nullable CharSequence title, @Nullable CharSequence text,
88             @Nullable View contentView) {
89         if (!(contentView instanceof ConversationLayout)) {
90             super.bind(title, text, contentView);
91             return;
92         }
93 
94         ConversationLayout conversationLayout = (ConversationLayout) contentView;
95         Icon conversationIcon = conversationLayout.getConversationIcon();
96         if (conversationIcon != null) {
97             mConversationFacePile.setVisibility(GONE);
98             mConversationIconView.setVisibility(VISIBLE);
99             mConversationIconView.setImageIcon(conversationIcon);
100             setSize(mConversationIconView, mSingleAvatarSize);
101         } else {
102             // If there isn't an icon, generate a "face pile" based on the sender avatars
103             mConversationIconView.setVisibility(GONE);
104             mConversationFacePile.setVisibility(VISIBLE);
105 
106             mConversationFacePile =
107                     requireViewById(com.android.internal.R.id.conversation_face_pile);
108             ImageView facePileBottomBg = mConversationFacePile.requireViewById(
109                     com.android.internal.R.id.conversation_face_pile_bottom_background);
110             ImageView facePileBottom = mConversationFacePile.requireViewById(
111                     com.android.internal.R.id.conversation_face_pile_bottom);
112             ImageView facePileTop = mConversationFacePile.requireViewById(
113                     com.android.internal.R.id.conversation_face_pile_top);
114             conversationLayout.bindFacePile(facePileBottomBg, facePileBottom, facePileTop);
115             setSize(mConversationFacePile, mFacePileSize);
116             setSize(facePileBottom, mFacePileAvatarSize);
117             setSize(facePileTop, mFacePileAvatarSize);
118             setSize(facePileBottomBg, mFacePileAvatarSize + 2 * mFacePileProtectionWidth);
119             mTransformationHelper.addViewTransformingToSimilar(facePileTop);
120             mTransformationHelper.addViewTransformingToSimilar(facePileBottom);
121             mTransformationHelper.addViewTransformingToSimilar(facePileBottomBg);
122         }
123         CharSequence conversationTitle = conversationLayout.getConversationTitle();
124         if (TextUtils.isEmpty(conversationTitle)) {
125             conversationTitle = title;
126         }
127         if (conversationLayout.isOneToOne()) {
128             mConversationSenderName.setVisibility(GONE);
129         } else {
130             mConversationSenderName.setVisibility(VISIBLE);
131             mConversationSenderName.setText(conversationLayout.getConversationSenderName());
132         }
133         CharSequence conversationText = conversationLayout.getConversationText();
134         if (TextUtils.isEmpty(conversationText)) {
135             conversationText = text;
136         }
137         super.bind(conversationTitle, conversationText, conversationLayout);
138     }
139 
setSize(View view, int size)140     private static void setSize(View view, int size) {
141         FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) view.getLayoutParams();
142         lp.width = size;
143         lp.height = size;
144         view.setLayoutParams(lp);
145     }
146 
147     /**
148      * Apply the faded state as a layer type change to the face pile view which needs to have
149      * overlapping contents render precisely.
150      */
151     @Override
setNotificationFaded(boolean faded)152     public void setNotificationFaded(boolean faded) {
153         super.setNotificationFaded(faded);
154         NotificationFadeAware.setLayerTypeForFaded(mConversationFacePile, faded);
155     }
156 }
157