1 /*
2  * Copyright (C) 2019 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.settingslib.widget;
18 
19 import static androidx.annotation.VisibleForTesting.NONE;
20 
21 import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_ICON_BACKGROUND_ARGB;
22 import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_ICON_BACKGROUND_HINT;
23 
24 import android.content.Context;
25 import android.content.pm.PackageManager;
26 import android.graphics.PorterDuff;
27 import android.graphics.drawable.Drawable;
28 import android.graphics.drawable.LayerDrawable;
29 import android.os.Bundle;
30 import android.util.Log;
31 
32 import androidx.annotation.VisibleForTesting;
33 
34 import com.android.settingslib.drawer.Tile;
35 
36 /**
37  * Adaptive icon that can set background color
38  */
39 public class AdaptiveIcon extends LayerDrawable {
40 
41     private static final String TAG = "AdaptiveHomepageIcon";
42 
43     @VisibleForTesting(otherwise = NONE)
44     int mBackgroundColor = -1;
45     private AdaptiveConstantState mAdaptiveConstantState;
46 
AdaptiveIcon(Context context, Drawable foreground)47     public AdaptiveIcon(Context context, Drawable foreground) {
48         this(context, foreground, R.dimen.dashboard_tile_foreground_image_inset);
49     }
50 
AdaptiveIcon(Context context, Drawable foreground, int insetResId)51     public AdaptiveIcon(Context context, Drawable foreground, int insetResId) {
52         super(new Drawable[]{
53                 new AdaptiveIconShapeDrawable(context.getResources()),
54                 foreground
55         });
56         final int insetPx = context.getResources().getDimensionPixelSize(insetResId);
57         setLayerInset(1 /* index */, insetPx, insetPx, insetPx, insetPx);
58         mAdaptiveConstantState = new AdaptiveConstantState(context, foreground);
59     }
60 
61     /**
62      *  According {@code tile} metaData to set background color
63      */
setBackgroundColor(Context context, Tile tile)64     public void setBackgroundColor(Context context, Tile tile) {
65         final Bundle metaData = tile.getMetaData();
66         try {
67             if (metaData != null) {
68                 // Load from bg.argb first
69                 int bgColor = metaData.getInt(META_DATA_PREFERENCE_ICON_BACKGROUND_ARGB,
70                         0 /* default */);
71                 // Not found, load from bg.hint
72                 if (bgColor == 0) {
73                     final int colorRes = metaData.getInt(META_DATA_PREFERENCE_ICON_BACKGROUND_HINT,
74                             0 /* default */);
75                     if (colorRes != 0) {
76                         bgColor = context.getPackageManager()
77                                 .getResourcesForApplication(tile.getPackageName())
78                                 .getColor(colorRes, null /* theme */);
79                     }
80                 }
81                 // If found anything, use it.
82                 if (bgColor != 0) {
83                     setBackgroundColor(bgColor);
84                     return;
85                 }
86             }
87         } catch (PackageManager.NameNotFoundException e) {
88             Log.e(TAG, "Failed to set background color for " + tile.getPackageName());
89         }
90         setBackgroundColor(context.getColor(R.color.homepage_generic_icon_background));
91     }
92 
93     /**
94      * Set background color by {@code color}
95      */
setBackgroundColor(int color)96     public void setBackgroundColor(int color) {
97         mBackgroundColor = color;
98         getDrawable(0).setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
99         Log.d(TAG, "Setting background color " + mBackgroundColor);
100         mAdaptiveConstantState.mColor = color;
101     }
102 
103     @Override
getConstantState()104     public ConstantState getConstantState() {
105         return mAdaptiveConstantState;
106     }
107 
108     @VisibleForTesting
109     static class AdaptiveConstantState extends ConstantState {
110         Context mContext;
111         Drawable mDrawable;
112         int mColor;
113 
AdaptiveConstantState(Context context, Drawable drawable)114         AdaptiveConstantState(Context context, Drawable drawable) {
115             this.mContext = context;
116             this.mDrawable = drawable;
117         }
118 
119         @Override
newDrawable()120         public Drawable newDrawable() {
121             final AdaptiveIcon
122                     icon = new AdaptiveIcon(mContext, mDrawable);
123             icon.setBackgroundColor(mColor);
124 
125             return icon;
126         }
127 
128         @Override
getChangingConfigurations()129         public int getChangingConfigurations() {
130             return 0;
131         }
132     }
133 }
134