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