1 /*
2  * Copyright (C) 2018 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.systemui.bubbles;
17 
18 import android.annotation.NonNull;
19 import android.annotation.Nullable;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.content.pm.LauncherApps;
23 import android.content.pm.ShortcutInfo;
24 import android.graphics.Bitmap;
25 import android.graphics.Canvas;
26 import android.graphics.Paint;
27 import android.graphics.Rect;
28 import android.graphics.drawable.BitmapDrawable;
29 import android.graphics.drawable.Drawable;
30 import android.graphics.drawable.Icon;
31 
32 import com.android.launcher3.icons.BaseIconFactory;
33 import com.android.launcher3.icons.BitmapInfo;
34 import com.android.launcher3.icons.ShadowGenerator;
35 import com.android.systemui.R;
36 
37 /**
38  * Factory for creating normalized bubble icons.
39  * We are not using Launcher's IconFactory because bubbles only runs on the UI thread,
40  * so there is no need to manage a pool across multiple threads.
41  */
42 public class BubbleIconFactory extends BaseIconFactory {
43 
BubbleIconFactory(Context context)44     protected BubbleIconFactory(Context context) {
45         super(context, context.getResources().getConfiguration().densityDpi,
46                 context.getResources().getDimensionPixelSize(R.dimen.individual_bubble_size));
47     }
48 
getBadgeSize()49     int getBadgeSize() {
50         return mContext.getResources().getDimensionPixelSize(
51                 com.android.launcher3.icons.R.dimen.profile_badge_size);
52     }
53     /**
54      * Returns the drawable that the developer has provided to display in the bubble.
55      */
getBubbleDrawable(@onNull final Context context, @Nullable final ShortcutInfo shortcutInfo, @Nullable final Icon ic)56     Drawable getBubbleDrawable(@NonNull final Context context,
57             @Nullable final ShortcutInfo shortcutInfo, @Nullable final Icon ic) {
58         if (shortcutInfo != null) {
59             LauncherApps launcherApps =
60                     (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE);
61             int density = context.getResources().getConfiguration().densityDpi;
62             return launcherApps.getShortcutIconDrawable(shortcutInfo, density);
63         } else {
64             if (ic != null) {
65                 if (ic.getType() == Icon.TYPE_URI
66                         || ic.getType() == Icon.TYPE_URI_ADAPTIVE_BITMAP) {
67                     context.grantUriPermission(context.getPackageName(),
68                             ic.getUri(),
69                             Intent.FLAG_GRANT_READ_URI_PERMISSION);
70                 }
71                 return ic.loadDrawable(context);
72             }
73             return null;
74         }
75     }
76 
77     /**
78      * Returns a {@link BitmapInfo} for the app-badge that is shown on top of each bubble. This
79      * will include the workprofile indicator on the badge if appropriate.
80      */
getBadgeBitmap(Drawable userBadgedAppIcon, boolean isImportantConversation)81     BitmapInfo getBadgeBitmap(Drawable userBadgedAppIcon, boolean isImportantConversation) {
82         Bitmap userBadgedBitmap = createIconBitmap(
83                 userBadgedAppIcon, 1f, getBadgeSize());
84         ShadowGenerator shadowGenerator = new ShadowGenerator(getBadgeSize());
85         if (!isImportantConversation) {
86             Canvas c = new Canvas();
87             c.setBitmap(userBadgedBitmap);
88             shadowGenerator.recreateIcon(Bitmap.createBitmap(userBadgedBitmap), c);
89             return createIconBitmap(userBadgedBitmap);
90         } else {
91             float ringStrokeWidth = mContext.getResources().getDimensionPixelSize(
92                     com.android.internal.R.dimen.importance_ring_stroke_width);
93             int importantConversationColor = mContext.getResources().getColor(
94                     com.android.settingslib.R.color.important_conversation, null);
95             Bitmap badgeAndRing = Bitmap.createBitmap(userBadgedBitmap.getWidth(),
96                     userBadgedBitmap.getHeight(), userBadgedBitmap.getConfig());
97             Canvas c = new Canvas(badgeAndRing);
98             Rect dest = new Rect((int) ringStrokeWidth, (int) ringStrokeWidth,
99                     c.getHeight() - (int) ringStrokeWidth, c.getWidth() - (int) ringStrokeWidth);
100             c.drawBitmap(userBadgedBitmap, null, dest, null);
101             Paint ringPaint = new Paint();
102             ringPaint.setStyle(Paint.Style.STROKE);
103             ringPaint.setColor(importantConversationColor);
104             ringPaint.setAntiAlias(true);
105             ringPaint.setStrokeWidth(ringStrokeWidth);
106             c.drawCircle(c.getWidth() / 2, c.getHeight() / 2, c.getWidth() / 2 - ringStrokeWidth,
107                     ringPaint);
108             shadowGenerator.recreateIcon(Bitmap.createBitmap(badgeAndRing), c);
109             return createIconBitmap(badgeAndRing);
110         }
111     }
112 
113     /**
114      * Returns a {@link BitmapInfo} for the entire bubble icon including the badge.
115      */
getBubbleBitmap(Drawable bubble, BitmapInfo badge)116     BitmapInfo getBubbleBitmap(Drawable bubble, BitmapInfo badge) {
117         BitmapInfo bubbleIconInfo = createBadgedIconBitmap(bubble,
118                 null /* user */,
119                 true /* shrinkNonAdaptiveIcons */);
120 
121         badgeWithDrawable(bubbleIconInfo.icon,
122                 new BitmapDrawable(mContext.getResources(), badge.icon));
123         return bubbleIconInfo;
124     }
125 }
126