• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 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.settings.shortcut;
18 
19 import static com.google.common.base.Preconditions.checkArgument;
20 
21 import android.content.Context;
22 import android.content.Intent;
23 import android.content.pm.ActivityInfo;
24 import android.content.pm.ApplicationInfo;
25 import android.content.pm.PackageManager;
26 import android.content.pm.ResolveInfo;
27 import android.content.pm.ShortcutInfo;
28 import android.graphics.Bitmap;
29 import android.graphics.Canvas;
30 import android.graphics.drawable.Drawable;
31 import android.graphics.drawable.Icon;
32 import android.graphics.drawable.LayerDrawable;
33 import android.util.Log;
34 import android.view.ContextThemeWrapper;
35 import android.view.LayoutInflater;
36 import android.view.View;
37 import android.widget.ImageView;
38 
39 import com.android.settings.R;
40 import com.android.settings.activityembedding.ActivityEmbeddingUtils;
41 
42 class Shortcuts {
43 
44     private static final String TAG = "Shortcuts";
45 
46     static final String SHORTCUT_ID_PREFIX = "component-shortcut-";
47     static final Intent SHORTCUT_PROBE = new Intent(Intent.ACTION_MAIN)
48             .addCategory("com.android.settings.SHORTCUT")
49             .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
50 
createShortcutInfo(Context context, ResolveInfo target)51     static ShortcutInfo createShortcutInfo(Context context, ResolveInfo target) {
52         checkArgument(target.activityInfo != null);
53         String shortcutId = SHORTCUT_ID_PREFIX
54                 + target.activityInfo.getComponentName().flattenToShortString();
55 
56         return createShortcutInfo(context, shortcutId, target);
57     }
58 
createShortcutInfo(Context context, String id, ResolveInfo target)59     static ShortcutInfo createShortcutInfo(Context context, String id, ResolveInfo target) {
60         Intent intent = new Intent(SHORTCUT_PROBE)
61                 .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP)
62                 .setClassName(target.activityInfo.packageName, target.activityInfo.name);
63         if (ActivityEmbeddingUtils.isEmbeddingActivityEnabled(context)) {
64             intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
65         }
66 
67         CharSequence label = target.loadLabel(context.getPackageManager());
68         Icon maskableIcon = getMaskableIcon(context, target.activityInfo);
69 
70         return new ShortcutInfo.Builder(context, id)
71                 .setIntent(intent)
72                 .setShortLabel(label)
73                 .setIcon(maskableIcon)
74                 .build();
75     }
76 
getMaskableIcon(Context context, ActivityInfo activityInfo)77     private static Icon getMaskableIcon(Context context, ActivityInfo activityInfo) {
78         if (activityInfo.icon != 0 && activityInfo.applicationInfo != null) {
79             return Icon.createWithAdaptiveBitmap(createIcon(
80                     context,
81                     activityInfo.applicationInfo, activityInfo.icon,
82                     R.layout.shortcut_badge_maskable,
83                     context.getResources().getDimensionPixelSize(R.dimen.shortcut_size_maskable)));
84         } else {
85             return Icon.createWithResource(context, R.drawable.ic_launcher_settings);
86         }
87     }
88 
createIcon(Context context, ApplicationInfo app, int resource, int layoutRes, int size)89     static Bitmap createIcon(Context context, ApplicationInfo app, int resource, int layoutRes,
90             int size) {
91         final Context themedContext = new ContextThemeWrapper(context,
92                 android.R.style.Theme_Material);
93         final View view = LayoutInflater.from(themedContext).inflate(layoutRes, null);
94         final int spec = View.MeasureSpec.makeMeasureSpec(size, View.MeasureSpec.EXACTLY);
95         view.measure(spec, spec);
96         final Bitmap bitmap = Bitmap.createBitmap(view.getMeasuredWidth(), view.getMeasuredHeight(),
97                 Bitmap.Config.ARGB_8888);
98         final Canvas canvas = new Canvas(bitmap);
99 
100         Drawable iconDrawable;
101         try {
102             iconDrawable = context.getPackageManager().getResourcesForApplication(app)
103                     .getDrawable(resource, themedContext.getTheme());
104             if (iconDrawable instanceof LayerDrawable) {
105                 iconDrawable = ((LayerDrawable) iconDrawable).getDrawable(1);
106             }
107             ((ImageView) view.findViewById(android.R.id.icon)).setImageDrawable(iconDrawable);
108         } catch (PackageManager.NameNotFoundException e) {
109             Log.w(TAG, "Cannot load icon from app " + app + ", returning a default icon");
110             Icon icon = Icon.createWithResource(context, R.drawable.ic_launcher_settings);
111             ((ImageView) view.findViewById(android.R.id.icon)).setImageIcon(icon);
112         }
113 
114         view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
115         view.draw(canvas);
116         return bitmap;
117     }
118 }
119