1 /*
2  * Copyright (C) 2023 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.intentresolver.icons;
18 
19 import android.content.ComponentName;
20 import android.content.Context;
21 import android.content.pm.ActivityInfo;
22 import android.content.pm.LauncherApps;
23 import android.content.pm.PackageManager;
24 import android.content.pm.ShortcutInfo;
25 import android.graphics.Bitmap;
26 import android.graphics.drawable.BitmapDrawable;
27 import android.graphics.drawable.Drawable;
28 import android.graphics.drawable.Icon;
29 import android.os.Trace;
30 import android.util.Log;
31 
32 import androidx.annotation.Nullable;
33 import androidx.annotation.WorkerThread;
34 
35 import com.android.intentresolver.SimpleIconFactory;
36 import com.android.intentresolver.TargetPresentationGetter;
37 import com.android.intentresolver.chooser.SelectableTargetInfo;
38 import com.android.intentresolver.util.UriFilters;
39 
40 import java.util.function.Consumer;
41 
42 /**
43  * Loads direct share targets icons.
44  */
45 class LoadDirectShareIconTask extends BaseLoadIconTask {
46     private static final String TAG = "DirectShareIconTask";
47     private final SelectableTargetInfo mTargetInfo;
48 
LoadDirectShareIconTask( Context context, SelectableTargetInfo targetInfo, TargetPresentationGetter.Factory presentationFactory, Consumer<Drawable> callback)49     LoadDirectShareIconTask(
50             Context context,
51             SelectableTargetInfo targetInfo,
52             TargetPresentationGetter.Factory presentationFactory,
53             Consumer<Drawable> callback) {
54         super(context, presentationFactory, callback);
55         mTargetInfo = targetInfo;
56     }
57 
58     @Override
doInBackground(Void... voids)59     protected Drawable doInBackground(Void... voids) {
60         Drawable drawable = null;
61         Trace.beginSection("shortcut-icon");
62         try {
63             final Icon icon = mTargetInfo.getChooserTargetIcon();
64             if (icon == null || UriFilters.hasValidIcon(icon)) {
65                 drawable = getChooserTargetIconDrawable(
66                         mContext,
67                         icon,
68                         mTargetInfo.getChooserTargetComponentName(),
69                         mTargetInfo.getDirectShareShortcutInfo());
70             } else {
71                 Log.e(TAG, "Failed to load shortcut icon for "
72                         + mTargetInfo.getChooserTargetComponentName() + "; no access");
73             }
74             if (drawable == null) {
75                 drawable = loadIconPlaceholder();
76             }
77         } catch (Exception e) {
78             Log.e(
79                     TAG,
80                     "Failed to load shortcut icon for "
81                             + mTargetInfo.getChooserTargetComponentName(),
82                     e);
83             drawable = loadIconPlaceholder();
84         } finally {
85             Trace.endSection();
86         }
87         return drawable;
88     }
89 
90     @WorkerThread
91     @Nullable
getChooserTargetIconDrawable( Context context, @Nullable Icon icon, ComponentName targetComponentName, @Nullable ShortcutInfo shortcutInfo)92     private Drawable getChooserTargetIconDrawable(
93             Context context,
94             @Nullable Icon icon,
95             ComponentName targetComponentName,
96             @Nullable ShortcutInfo shortcutInfo) {
97         Drawable directShareIcon = null;
98 
99         // First get the target drawable and associated activity info
100         if (icon != null) {
101             directShareIcon = icon.loadDrawable(context);
102         } else if (shortcutInfo != null) {
103             LauncherApps launcherApps = context.getSystemService(LauncherApps.class);
104             if (launcherApps != null) {
105                 directShareIcon = launcherApps.getShortcutIconDrawable(shortcutInfo, 0);
106             }
107         }
108 
109         if (directShareIcon == null) {
110             return null;
111         }
112 
113         ActivityInfo info = null;
114         try {
115             info = context.getPackageManager().getActivityInfo(targetComponentName, 0);
116         } catch (PackageManager.NameNotFoundException error) {
117             Log.e(TAG, "Could not find activity associated with ChooserTarget");
118         }
119 
120         if (info == null) {
121             return null;
122         }
123 
124         // Now fetch app icon and raster with no badging even in work profile
125         Bitmap appIcon = mPresentationFactory.makePresentationGetter(info).getIconBitmap(null);
126 
127         // Raster target drawable with appIcon as a badge
128         SimpleIconFactory sif = SimpleIconFactory.obtain(context);
129         Bitmap directShareBadgedIcon = sif.createAppBadgedIconBitmap(directShareIcon, appIcon);
130         sif.recycle();
131 
132         return new BitmapDrawable(context.getResources(), directShareBadgedIcon);
133     }
134 }
135