1 /*
2  * Copyright (C) 2016 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.launcher3.graphics;
18 
19 import static com.android.launcher3.graphics.IconShape.getShapePath;
20 import static com.android.launcher3.util.MainThreadInitializedObject.forOverride;
21 
22 import android.content.Context;
23 import android.content.pm.ActivityInfo;
24 import android.content.res.Resources;
25 import android.graphics.Bitmap;
26 import android.graphics.Canvas;
27 import android.graphics.Color;
28 import android.graphics.Rect;
29 import android.graphics.drawable.BitmapDrawable;
30 import android.graphics.drawable.Drawable;
31 import android.os.Process;
32 import android.os.UserHandle;
33 import android.util.ArrayMap;
34 
35 import androidx.annotation.UiThread;
36 
37 import com.android.launcher3.FastBitmapDrawable;
38 import com.android.launcher3.ItemInfoWithIcon;
39 import com.android.launcher3.R;
40 import com.android.launcher3.icons.BitmapInfo;
41 import com.android.launcher3.util.MainThreadInitializedObject;
42 import com.android.launcher3.util.ResourceBasedOverride;
43 
44 /**
45  * Factory for creating new drawables.
46  */
47 public class DrawableFactory implements ResourceBasedOverride {
48 
49     public static final MainThreadInitializedObject<DrawableFactory> INSTANCE =
50             forOverride(DrawableFactory.class, R.string.drawable_factory_class);
51 
52     protected final UserHandle mMyUser = Process.myUserHandle();
53     protected final ArrayMap<UserHandle, Bitmap> mUserBadges = new ArrayMap<>();
54 
55     /**
56      * Returns a FastBitmapDrawable with the icon.
57      */
newIcon(Context context, ItemInfoWithIcon info)58     public FastBitmapDrawable newIcon(Context context, ItemInfoWithIcon info) {
59         FastBitmapDrawable drawable = info.usingLowResIcon()
60                 ? new PlaceHolderIconDrawable(info, getShapePath(), context)
61                 : new FastBitmapDrawable(info);
62         drawable.setIsDisabled(info.isDisabled());
63         return drawable;
64     }
65 
newIcon(Context context, BitmapInfo info, ActivityInfo target)66     public FastBitmapDrawable newIcon(Context context, BitmapInfo info, ActivityInfo target) {
67         return info.isLowRes()
68                 ? new PlaceHolderIconDrawable(info, getShapePath(), context)
69                 : new FastBitmapDrawable(info);
70     }
71 
72     /**
73      * Returns a FastBitmapDrawable with the icon.
74      */
newPendingIcon(Context context, ItemInfoWithIcon info)75     public PreloadIconDrawable newPendingIcon(Context context, ItemInfoWithIcon info) {
76         return new PreloadIconDrawable(info, getShapePath(), context);
77     }
78 
79     /**
80      * Returns a drawable that can be used as a badge for the user or null.
81      */
82     @UiThread
getBadgeForUser(UserHandle user, Context context, int badgeSize)83     public Drawable getBadgeForUser(UserHandle user, Context context, int badgeSize) {
84         if (mMyUser.equals(user)) {
85             return null;
86         }
87 
88         Bitmap badgeBitmap = getUserBadge(user, context, badgeSize);
89         FastBitmapDrawable d = new FastBitmapDrawable(badgeBitmap);
90         d.setFilterBitmap(true);
91         d.setBounds(0, 0, badgeBitmap.getWidth(), badgeBitmap.getHeight());
92         return d;
93     }
94 
getUserBadge(UserHandle user, Context context, int badgeSize)95     protected synchronized Bitmap getUserBadge(UserHandle user, Context context, int badgeSize) {
96         Bitmap badgeBitmap = mUserBadges.get(user);
97         if (badgeBitmap != null) {
98             return badgeBitmap;
99         }
100 
101         final Resources res = context.getApplicationContext().getResources();
102         badgeBitmap = Bitmap.createBitmap(badgeSize, badgeSize, Bitmap.Config.ARGB_8888);
103 
104         Drawable drawable = context.getPackageManager().getUserBadgedDrawableForDensity(
105                 new BitmapDrawable(res, badgeBitmap), user, new Rect(0, 0, badgeSize, badgeSize),
106                 0);
107         if (drawable instanceof BitmapDrawable) {
108             badgeBitmap = ((BitmapDrawable) drawable).getBitmap();
109         } else {
110             badgeBitmap.eraseColor(Color.TRANSPARENT);
111             Canvas c = new Canvas(badgeBitmap);
112             drawable.setBounds(0, 0, badgeSize, badgeSize);
113             drawable.draw(c);
114             c.setBitmap(null);
115         }
116 
117         mUserBadges.put(user, badgeBitmap);
118         return badgeBitmap;
119     }
120 }
121