• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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.icons;
17 
18 import static com.android.launcher3.icons.cache.CacheLookupFlag.DEFAULT_LOOKUP_FLAG;
19 
20 import android.content.Context;
21 import android.graphics.Bitmap;
22 import android.graphics.Bitmap.Config;
23 import android.graphics.Canvas;
24 import android.graphics.Path;
25 import android.graphics.drawable.Drawable;
26 
27 import androidx.annotation.IntDef;
28 import androidx.annotation.NonNull;
29 import androidx.annotation.Nullable;
30 
31 import com.android.launcher3.icons.cache.CacheLookupFlag;
32 import com.android.launcher3.util.FlagOp;
33 
34 public class BitmapInfo {
35 
36     public static final int FLAG_WORK = 1 << 0;
37     public static final int FLAG_INSTANT = 1 << 1;
38     public static final int FLAG_CLONE = 1 << 2;
39     public static final int FLAG_PRIVATE = 1 << 3;
40     @IntDef(flag = true, value = {
41             FLAG_WORK,
42             FLAG_INSTANT,
43             FLAG_CLONE,
44             FLAG_PRIVATE
45     })
46     @interface BitmapInfoFlags {}
47 
48     public static final int FLAG_THEMED = 1 << 0;
49     public static final int FLAG_NO_BADGE = 1 << 1;
50     public static final int FLAG_SKIP_USER_BADGE = 1 << 2;
51     @IntDef(flag = true, value = {
52             FLAG_THEMED,
53             FLAG_NO_BADGE,
54             FLAG_SKIP_USER_BADGE,
55     })
56     public @interface DrawableCreationFlags {}
57 
58     public static final Bitmap LOW_RES_ICON = Bitmap.createBitmap(1, 1, Config.ALPHA_8);
59     public static final BitmapInfo LOW_RES_INFO = fromBitmap(LOW_RES_ICON);
60 
61     public static final String TAG = "BitmapInfo";
62 
63     @NonNull
64     public final Bitmap icon;
65     public final int color;
66 
67     @Nullable
68     private ThemedBitmap mThemedBitmap;
69 
70     public @BitmapInfoFlags int flags;
71 
72     // b/377618519: These are saved to debug why work badges sometimes don't show up on work apps
73     public @DrawableCreationFlags int creationFlags;
74 
75     private BitmapInfo badgeInfo;
76 
BitmapInfo(@onNull Bitmap icon, int color)77     public BitmapInfo(@NonNull Bitmap icon, int color) {
78         this.icon = icon;
79         this.color = color;
80     }
81 
withBadgeInfo(BitmapInfo badgeInfo)82     public BitmapInfo withBadgeInfo(BitmapInfo badgeInfo) {
83         BitmapInfo result = clone();
84         result.badgeInfo = badgeInfo;
85         return result;
86     }
87 
88     /**
89      * Returns a bitmapInfo with the flagOP applied
90      */
withFlags(@onNull FlagOp op)91     public BitmapInfo withFlags(@NonNull FlagOp op) {
92         if (op == FlagOp.NO_OP) {
93             return this;
94         }
95         BitmapInfo result = clone();
96         result.flags = op.apply(result.flags);
97         return result;
98     }
99 
copyInternalsTo(BitmapInfo target)100     protected BitmapInfo copyInternalsTo(BitmapInfo target) {
101         target.mThemedBitmap = mThemedBitmap;
102         target.flags = flags;
103         target.badgeInfo = badgeInfo;
104         return target;
105     }
106 
107     @Override
clone()108     public BitmapInfo clone() {
109         return copyInternalsTo(new BitmapInfo(icon, color));
110     }
111 
setThemedBitmap(@ullable ThemedBitmap themedBitmap)112     public void setThemedBitmap(@Nullable ThemedBitmap themedBitmap) {
113         mThemedBitmap = themedBitmap;
114     }
115 
116     @Nullable
getThemedBitmap()117     public ThemedBitmap getThemedBitmap() {
118         return mThemedBitmap;
119     }
120 
121     /**
122      * Ideally icon should not be null, except in cases when generating hardware bitmap failed
123      */
isNullOrLowRes()124     public final boolean isNullOrLowRes() {
125         return icon == null || icon == LOW_RES_ICON;
126     }
127 
isLowRes()128     public final boolean isLowRes() {
129         return LOW_RES_ICON == icon;
130     }
131 
132     /**
133      * Returns the lookup flag to match this current state of this info
134      */
getMatchingLookupFlag()135     public CacheLookupFlag getMatchingLookupFlag() {
136         return DEFAULT_LOOKUP_FLAG.withUseLowRes(isLowRes());
137     }
138 
139     /**
140      * BitmapInfo can be stored on disk or other persistent storage
141      */
canPersist()142     public boolean canPersist() {
143         return !isNullOrLowRes();
144     }
145 
146     /**
147      * Creates a drawable for the provided BitmapInfo
148      */
newIcon(Context context)149     public FastBitmapDrawable newIcon(Context context) {
150         return newIcon(context, 0);
151     }
152 
153     /**
154      * Creates a drawable for the provided BitmapInfo
155      */
newIcon(Context context, @DrawableCreationFlags int creationFlags)156     public FastBitmapDrawable newIcon(Context context, @DrawableCreationFlags int creationFlags) {
157         return newIcon(context, creationFlags, null);
158     }
159 
160     /**
161      * Creates a drawable for the provided BitmapInfo
162      *
163      * @param context Context
164      * @param creationFlags Flags for creating the FastBitmapDrawable
165      * @param badgeShape Optional Path for masking icon badges to a shape. Should be 100x100.
166      * @return FastBitmapDrawable
167      */
newIcon(Context context, @DrawableCreationFlags int creationFlags, @Nullable Path badgeShape)168     public FastBitmapDrawable newIcon(Context context, @DrawableCreationFlags int creationFlags,
169             @Nullable Path badgeShape) {
170         FastBitmapDrawable drawable;
171         if (isLowRes()) {
172             drawable = new PlaceHolderIconDrawable(this, context);
173         } else  if ((creationFlags & FLAG_THEMED) != 0 && mThemedBitmap != null) {
174             drawable = mThemedBitmap.newDrawable(this, context);
175         } else {
176             drawable = new FastBitmapDrawable(this);
177         }
178         applyFlags(context, drawable, creationFlags, badgeShape);
179         return drawable;
180     }
181 
applyFlags(Context context, FastBitmapDrawable drawable, @DrawableCreationFlags int creationFlags, @Nullable Path badgeShape)182     protected void applyFlags(Context context, FastBitmapDrawable drawable,
183             @DrawableCreationFlags int creationFlags, @Nullable Path badgeShape) {
184         this.creationFlags = creationFlags;
185         drawable.mDisabledAlpha = GraphicsUtils.getFloat(context, R.attr.disabledIconAlpha, 1f);
186         drawable.mCreationFlags = creationFlags;
187         if ((creationFlags & FLAG_NO_BADGE) == 0) {
188             Drawable badge = getBadgeDrawable(context, (creationFlags & FLAG_THEMED) != 0,
189                     (creationFlags & FLAG_SKIP_USER_BADGE) != 0, badgeShape);
190             if (badge != null) {
191                 drawable.setBadge(badge);
192             }
193         }
194     }
195 
196     /**
197      * Gets Badge drawable based on current flags
198      * @param context Context
199      * @param isThemed If Drawable is themed.
200      * @param badgeShape Optional Path to mask badges to a shape. Should be 100x100.
201      * @return Drawable for the badge.
202      */
getBadgeDrawable(Context context, boolean isThemed, @Nullable Path badgeShape)203     public Drawable getBadgeDrawable(Context context, boolean isThemed, @Nullable Path badgeShape) {
204         return getBadgeDrawable(context, isThemed, false, badgeShape);
205     }
206 
207 
208     /**
209      * Creates a Drawable for an icon badge for this BitmapInfo
210      * @param context Context
211      * @param isThemed If the drawable is themed.
212      * @param skipUserBadge If should skip User Profile badging.
213      * @param badgeShape Optional Path to mask badge Drawable to a shape. Should be 100x100.
214      * @return Drawable for an icon Badge.
215      */
216     @Nullable
getBadgeDrawable(Context context, boolean isThemed, boolean skipUserBadge, @Nullable Path badgeShape)217     private Drawable getBadgeDrawable(Context context, boolean isThemed, boolean skipUserBadge,
218             @Nullable Path badgeShape) {
219         if (badgeInfo != null) {
220             int creationFlag = isThemed ? FLAG_THEMED : 0;
221             if (skipUserBadge) {
222                 creationFlag |= FLAG_SKIP_USER_BADGE;
223             }
224             return badgeInfo.newIcon(context, creationFlag, badgeShape);
225         }
226         if (skipUserBadge) {
227             return null;
228         } else if ((flags & FLAG_INSTANT) != 0) {
229             return new UserBadgeDrawable(context, R.drawable.ic_instant_app_badge,
230                     R.color.badge_tint_instant, isThemed, badgeShape);
231         } else if ((flags & FLAG_WORK) != 0) {
232             return new UserBadgeDrawable(context, R.drawable.ic_work_app_badge,
233                     R.color.badge_tint_work, isThemed, badgeShape);
234         } else if ((flags & FLAG_CLONE) != 0) {
235             return new UserBadgeDrawable(context, R.drawable.ic_clone_app_badge,
236                     R.color.badge_tint_clone, isThemed, badgeShape);
237         } else if ((flags & FLAG_PRIVATE) != 0) {
238             return new UserBadgeDrawable(context, R.drawable.ic_private_profile_app_badge,
239                     R.color.badge_tint_private, isThemed, badgeShape);
240         }
241         return null;
242     }
243 
fromBitmap(@onNull Bitmap bitmap)244     public static BitmapInfo fromBitmap(@NonNull Bitmap bitmap) {
245         return of(bitmap, 0);
246     }
247 
of(@onNull Bitmap bitmap, int color)248     public static BitmapInfo of(@NonNull Bitmap bitmap, int color) {
249         return new BitmapInfo(bitmap, color);
250     }
251 
252     /**
253      * Interface to be implemented by drawables to provide a custom BitmapInfo
254      */
255     public interface Extender {
256 
257         /**
258          * Called for creating a custom BitmapInfo
259          */
getExtendedInfo(Bitmap bitmap, int color, BaseIconFactory iconFactory, float normalizationScale)260         BitmapInfo getExtendedInfo(Bitmap bitmap, int color,
261                 BaseIconFactory iconFactory, float normalizationScale);
262 
263         /**
264          * Called to draw the UI independent of any runtime configurations like time or theme
265          */
drawForPersistence(Canvas canvas)266         void drawForPersistence(Canvas canvas);
267     }
268 }
269