1 /*
2  * Copyright (C) 2022 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.wm.shell.common;
18 
19 import android.content.Context;
20 import android.content.res.TypedArray;
21 import android.graphics.drawable.Drawable;
22 import android.graphics.drawable.Icon;
23 import android.os.Handler;
24 import android.util.AttributeSet;
25 import android.view.LayoutInflater;
26 import android.view.View;
27 import android.widget.ImageView;
28 import android.widget.RelativeLayout;
29 
30 import com.android.wm.shell.R;
31 
32 /**
33  * A common action button for TV window menu layouts.
34  */
35 public class TvWindowMenuActionButton extends RelativeLayout {
36     private final ImageView mIconImageView;
37     private final View mButtonBackgroundView;
38 
39     private Icon mCurrentIcon;
40 
TvWindowMenuActionButton(Context context)41     public TvWindowMenuActionButton(Context context) {
42         this(context, null, 0, 0);
43     }
44 
TvWindowMenuActionButton(Context context, AttributeSet attrs)45     public TvWindowMenuActionButton(Context context, AttributeSet attrs) {
46         this(context, attrs, 0, 0);
47     }
48 
TvWindowMenuActionButton(Context context, AttributeSet attrs, int defStyleAttr)49     public TvWindowMenuActionButton(Context context, AttributeSet attrs, int defStyleAttr) {
50         this(context, attrs, defStyleAttr, 0);
51     }
52 
TvWindowMenuActionButton( Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)53     public TvWindowMenuActionButton(
54             Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
55         super(context, attrs, defStyleAttr, defStyleRes);
56         final LayoutInflater inflater = (LayoutInflater) getContext()
57                 .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
58         inflater.inflate(R.layout.tv_window_menu_action_button, this);
59 
60         mIconImageView = findViewById(R.id.icon);
61         mButtonBackgroundView = findViewById(R.id.background);
62 
63         final int[] values = new int[]{android.R.attr.src, android.R.attr.text};
64         final TypedArray typedArray = context.obtainStyledAttributes(attrs, values, defStyleAttr,
65                 defStyleRes);
66 
67         setImageResource(typedArray.getResourceId(0, 0));
68         final int textResId = typedArray.getResourceId(1, 0);
69         if (textResId != 0) {
70             setTextAndDescription(textResId);
71         }
72         typedArray.recycle();
73 
74         setIsCustomCloseAction(false);
75     }
76 
77     /**
78      * Sets the drawable for the button with the given drawable.
79      */
setImageDrawable(Drawable d)80     public void setImageDrawable(Drawable d) {
81         mIconImageView.setImageDrawable(d);
82     }
83 
84     /**
85      * Sets the drawable for the button with the given resource id.
86      */
setImageResource(int resId)87     public void setImageResource(int resId) {
88         if (resId != 0) {
89             mIconImageView.setImageResource(resId);
90         }
91     }
92 
setImageIconAsync(Icon icon, Handler handler)93     public void setImageIconAsync(Icon icon, Handler handler) {
94         mCurrentIcon = icon;
95         // Remove old image while waiting for the new one to load.
96         mIconImageView.setImageDrawable(null);
97         if (icon.getType() == Icon.TYPE_URI || icon.getType() == Icon.TYPE_URI_ADAPTIVE_BITMAP) {
98             // Disallow loading icon from content URI
99             return;
100         }
101         icon.loadDrawableAsync(mContext, d -> {
102             // The image hasn't been set any other way and the drawable belongs to the most
103             // recently set Icon.
104             if (mIconImageView.getDrawable() == null && mCurrentIcon == icon) {
105                 mIconImageView.setImageDrawable(d);
106             }
107         }, handler);
108     }
109 
110     /**
111      * Sets the text for description the with the given string.
112      */
setTextAndDescription(CharSequence text)113     public void setTextAndDescription(CharSequence text) {
114         setContentDescription(text);
115     }
116 
117     /**
118      * Sets the text and description with the given string resource id.
119      */
setTextAndDescription(int resId)120     public void setTextAndDescription(int resId) {
121         setTextAndDescription(getContext().getString(resId));
122     }
123 
124     /**
125      * Marks this button as a custom close action button.
126      * This changes the style of the action button to highlight that this action finishes the
127      * Picture-in-Picture activity.
128      *
129      * @param isCustomCloseAction sets or unsets this button as a custom close action button.
130      */
setIsCustomCloseAction(boolean isCustomCloseAction)131     public void setIsCustomCloseAction(boolean isCustomCloseAction) {
132         mIconImageView.setImageTintList(
133                 getResources().getColorStateList(
134                         isCustomCloseAction ? R.color.tv_window_menu_close_icon
135                                 : R.color.tv_window_menu_icon));
136         mButtonBackgroundView.setBackgroundTintList(getResources()
137                 .getColorStateList(isCustomCloseAction ? R.color.tv_window_menu_close_icon_bg
138                         : R.color.tv_window_menu_icon_bg));
139     }
140 
141     @Override
toString()142     public String toString() {
143         if (getContentDescription() == null) {
144             return TvWindowMenuActionButton.class.getSimpleName();
145         }
146         return getContentDescription().toString();
147     }
148 
149 }
150