1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 package org.chromium.chrome.browser.tasks.tab_management;
6 
7 import android.content.Context;
8 import android.graphics.Bitmap;
9 import android.graphics.BitmapFactory;
10 import android.graphics.drawable.Drawable;
11 import android.util.AttributeSet;
12 import android.widget.LinearLayout;
13 
14 import org.chromium.base.ApiCompatibilityUtils;
15 import org.chromium.chrome.tab_ui.R;
16 import org.chromium.components.browser_ui.widget.text.TemplatePreservingTextView;
17 import org.chromium.ui.widget.ButtonCompat;
18 import org.chromium.ui.widget.ChromeImageView;
19 
20 import java.lang.ref.WeakReference;
21 
22 /**
23  * Represents a secondary card view in Grid Tab Switcher. The view contains an icon, a description,
24  * an action button for acceptance, and a close button for dismissal.
25  */
26 class MessageCardView extends LinearLayout {
27     private static WeakReference<Bitmap> sCloseButtonBitmapWeakRef;
28 
29     /**
30      * An interface to get the icon to be shown inside the message card.
31      */
getIconDrawable()32     public interface IconProvider { Drawable getIconDrawable(); }
33 
34     /**
35      * An interface to handle the review action.
36      */
review()37     public interface ReviewActionProvider { void review(); }
38 
39     /**
40      * An interface to handle the dismiss action.
41      */
42     public interface DismissActionProvider {
dismiss(@essageService.MessageType int messageType)43         void dismiss(@MessageService.MessageType int messageType);
44     }
45 
46     private ChromeImageView mIcon;
47     private TemplatePreservingTextView mDescription;
48     private ButtonCompat mActionButton;
49     private ChromeImageView mCloseButton;
50 
MessageCardView(Context context, AttributeSet attrs)51     public MessageCardView(Context context, AttributeSet attrs) {
52         super(context, attrs);
53     }
54 
55     @Override
onFinishInflate()56     protected void onFinishInflate() {
57         super.onFinishInflate();
58 
59         mIcon = findViewById(R.id.icon);
60         mDescription = findViewById(R.id.description);
61         mActionButton = findViewById(R.id.action_button);
62         mCloseButton = findViewById(R.id.close_button);
63 
64         if (sCloseButtonBitmapWeakRef == null || sCloseButtonBitmapWeakRef.get() == null) {
65             int closeButtonSize =
66                     (int) getResources().getDimension(R.dimen.tab_grid_close_button_size);
67             Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.btn_close);
68             sCloseButtonBitmapWeakRef = new WeakReference<>(
69                     Bitmap.createScaledBitmap(bitmap, closeButtonSize, closeButtonSize, true));
70         }
71         mCloseButton.setImageBitmap(sCloseButtonBitmapWeakRef.get());
72     }
73 
74     /**
75      * @see TemplatePreservingTextView#setTemplate(String), setDescriptionText() must be called
76      * after calling this method for the new template text to take effect.
77      */
setDescriptionTextTemplate(String template)78     void setDescriptionTextTemplate(String template) {
79         mDescription.setTemplate(template);
80     }
81 
82     /**
83      * @see TemplatePreservingTextView#setText(CharSequence).
84      */
setDescriptionText(CharSequence text)85     void setDescriptionText(CharSequence text) {
86         mDescription.setText(text);
87     }
88 
89     /**
90      * Set action text for the action button.
91      * @param actionText Text to be displayed.
92      */
setActionText(String actionText)93     void setActionText(String actionText) {
94         mActionButton.setText(actionText);
95     }
96 
97     /**
98      * Set icon drawable.
99      * @param iconDrawable Drawable to be shown.
100      */
setIcon(Drawable iconDrawable)101     void setIcon(Drawable iconDrawable) {
102         mIcon.setImageDrawable(iconDrawable);
103     }
104 
105     /**
106      * Set click listener for the action button.
107      * @param listener {@link android.view.View.OnClickListener} for the action button.
108      */
setActionButtonOnClickListener(OnClickListener listener)109     void setActionButtonOnClickListener(OnClickListener listener) {
110         mActionButton.setOnClickListener(listener);
111     }
112 
113     /**
114      * Set content description for dismiss button.
115      * @param description The content description.
116      */
setDismissButtonContentDescription(String description)117     void setDismissButtonContentDescription(String description) {
118         mCloseButton.setContentDescription(description);
119     }
120 
121     /**
122      * Set {@link android.view.View.OnClickListener} for dismiss button.
123      * @param listener {@link android.view.View.OnClickListener} to set.
124      */
setDismissButtonOnClickListener(OnClickListener listener)125     void setDismissButtonOnClickListener(OnClickListener listener) {
126         mCloseButton.setOnClickListener(listener);
127     }
128 
129     /**
130      * Modify the view based on the visibility of the icon. For messages that doesn't have an icon,
131      * remove the icon and update the margin of the description text field.
132      * @param visible  Whether icon is visible.
133      */
setIconVisibility(boolean visible)134     void setIconVisibility(boolean visible) {
135         MarginLayoutParams params = (MarginLayoutParams) mDescription.getLayoutParams();
136         if (visible) {
137             if (indexOfChild(mIcon) == -1) {
138                 addView(mIcon, 0);
139                 params.setMargins(0, 0, 0, 0);
140             }
141         } else {
142             int margin = (int) getContext().getResources().getDimension(
143                     R.dimen.tab_grid_iph_item_description_margin);
144             removeView(mIcon);
145             params.setMargins(margin, 0, 0, 0);
146         }
147     }
148 
149     /**
150      * Set background resource.
151      * @param isIncognito Whether the resource is used for incognito mode.
152      */
setBackground(boolean isIncognito)153     private void setBackground(boolean isIncognito) {
154         setBackgroundResource(TabUiColorProvider.getMessageCardBackgroundResourceId(isIncognito));
155     }
156 
157     /**
158      * Set text appearance for description.
159      * @param isIncognito Whether the text appearance is used for incognito mode.
160      */
setDescriptionTextAppearance(boolean isIncognito)161     private void setDescriptionTextAppearance(boolean isIncognito) {
162         ApiCompatibilityUtils.setTextAppearance(mDescription,
163                 TabUiColorProvider.getMessageCardDescriptionTextAppearance(isIncognito));
164     }
165 
166     /**
167      * Set text appearance for action button.
168      * @param isIncognito Whether the text appearance is used for incognito mode.
169      */
setActionButtonTextAppearance(boolean isIncognito)170     private void setActionButtonTextAppearance(boolean isIncognito) {
171         ApiCompatibilityUtils.setTextAppearance(mActionButton,
172                 TabUiColorProvider.getMessageCardActionButtonTextAppearance(isIncognito));
173     }
174 
175     /**
176      * Set tint for close button.
177      * @param isIncognito Whether the tint is used for incognito mode.
178      */
setCloseButtonTint(boolean isIncognito)179     private void setCloseButtonTint(boolean isIncognito) {
180         ApiCompatibilityUtils.setImageTintList(mCloseButton,
181                 TabUiColorProvider.getMessageCardCloseButtonTintList(
182                         mCloseButton.getContext(), isIncognito));
183     }
184 
185     /**
186      * Update Message Card when switching between normal mode and incognito mode.
187      * @param isIncognito Whether it is in the incognito mode.
188      */
updateMessageCardColor(boolean isIncognito)189     void updateMessageCardColor(boolean isIncognito) {
190         setBackground(isIncognito);
191         setDescriptionTextAppearance(isIncognito);
192         setActionButtonTextAppearance(isIncognito);
193         // TODO(crbug.com/1139194): Set action button ripple color.
194         setCloseButtonTint(isIncognito);
195     }
196 }
197