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 package com.android.launcher3.views;
17 
18 import android.annotation.TargetApi;
19 import android.content.Context;
20 import android.content.res.ColorStateList;
21 import android.content.res.TypedArray;
22 import android.graphics.Bitmap;
23 import android.graphics.BlendMode;
24 import android.graphics.BlendModeColorFilter;
25 import android.graphics.Canvas;
26 import android.graphics.Color;
27 import android.graphics.Rect;
28 import android.graphics.drawable.ColorDrawable;
29 import android.graphics.drawable.Drawable;
30 import android.os.Build;
31 import android.util.AttributeSet;
32 import android.view.accessibility.AccessibilityEvent;
33 
34 import androidx.annotation.ColorInt;
35 import androidx.annotation.NonNull;
36 
37 import com.android.launcher3.BubbleTextView;
38 import com.android.launcher3.icons.BaseIconFactory;
39 import com.android.launcher3.icons.FastBitmapDrawable;
40 import com.android.launcher3.icons.LauncherIcons;
41 import com.android.launcher3.util.MultiTranslateDelegate;
42 
43 /**
44  * Button in Taskbar that shows a tinted background and foreground.
45  */
46 public class IconButtonView extends BubbleTextView {
47 
48     private static final int[] ATTRS = {android.R.attr.icon};
49 
50     private static final int INDEX_TASKBAR_ALL_APPS_ICON = MultiTranslateDelegate.COUNT;
51     private static final int MY_COUNT = MultiTranslateDelegate.COUNT + 1;
52 
53     private final MultiTranslateDelegate mTranslateDelegate =
54             new MultiTranslateDelegate(this, MY_COUNT, MultiTranslateDelegate.COUNT);
55 
IconButtonView(Context context)56     public IconButtonView(Context context) {
57         this(context, null);
58     }
59 
IconButtonView(Context context, AttributeSet attrs)60     public IconButtonView(Context context, AttributeSet attrs) {
61         this(context, attrs, 0);
62     }
63 
IconButtonView(Context context, AttributeSet attrs, int defStyle)64     public IconButtonView(Context context, AttributeSet attrs, int defStyle) {
65         super(context, attrs, defStyle);
66 
67         TypedArray a = context.obtainStyledAttributes(attrs, ATTRS, defStyle, 0);
68         Drawable fg = a.getDrawable(0);
69         a.recycle();
70 
71         ColorStateList tintList = getBackgroundTintList();
72         int tint = tintList == null ? Color.WHITE : tintList.getDefaultColor();
73 
74         if (fg == null) {
75             fg = new ColorDrawable(Color.TRANSPARENT);
76         }
77         try (BaseIconFactory factory = LauncherIcons.obtain(context)) {
78             setIcon(new IconDrawable(factory.getWhiteShadowLayer(), tint, fg));
79         }
80     }
81 
82     @Override
onPopulateAccessibilityEvent(AccessibilityEvent event)83     public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
84         super.onPopulateAccessibilityEvent(event);
85         event.getText().add(this.getContentDescription());
86     }
87 
88     /** Sets given Drawable as icon */
setIconDrawable(@onNull Drawable drawable)89     public void setIconDrawable(@NonNull Drawable drawable) {
90         ColorStateList tintList = getBackgroundTintList();
91         int tint = tintList == null ? Color.WHITE : tintList.getDefaultColor();
92         try (BaseIconFactory factory = LauncherIcons.obtain(getContext())) {
93             setIcon(new IconDrawable(factory.getWhiteShadowLayer(), tint, drawable));
94         }
95     }
96 
97     /** Updates the color of the icon's foreground layer. */
setForegroundTint(@olorInt int tintColor)98     public void setForegroundTint(@ColorInt int tintColor) {
99         FastBitmapDrawable icon = getIcon();
100         if (icon instanceof IconDrawable) {
101             ((IconDrawable) icon).mFg.setTint(tintColor);
102         }
103     }
104 
105     @Override
getTranslateDelegate()106     public MultiTranslateDelegate getTranslateDelegate() {
107         return mTranslateDelegate;
108     }
109 
110     /**
111      * Sets translationX for taskbar all apps icon
112      */
setTranslationXForTaskbarAllAppsIcon(float translationX)113     public void setTranslationXForTaskbarAllAppsIcon(float translationX) {
114         getTranslateDelegate().getTranslationX(INDEX_TASKBAR_ALL_APPS_ICON).setValue(translationX);
115     }
116 
117     private static class IconDrawable extends FastBitmapDrawable {
118 
119         private final Drawable mFg;
120 
121         @TargetApi(Build.VERSION_CODES.TIRAMISU)
IconDrawable(Bitmap b, int colorBg, Drawable fg)122         IconDrawable(Bitmap b, int colorBg, Drawable fg) {
123             super(b);
124             mPaint.setColorFilter(new BlendModeColorFilter(colorBg, BlendMode.SRC_IN));
125             mFg = fg;
126         }
127 
128         @Override
drawInternal(Canvas canvas, Rect bounds)129         protected void drawInternal(Canvas canvas, Rect bounds) {
130             super.drawInternal(canvas, bounds);
131             mFg.draw(canvas);
132         }
133 
134         @Override
onBoundsChange(Rect bounds)135         protected void onBoundsChange(Rect bounds) {
136             super.onBoundsChange(bounds);
137             mFg.setBounds(bounds);
138         }
139     }
140 }
141