1 /*
2  * Copyright (C) 2017 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.pm;
18 
19 import static com.android.launcher3.Utilities.allowBGLaunch;
20 
21 import android.annotation.TargetApi;
22 import android.app.Activity;
23 import android.app.ActivityOptions;
24 import android.content.ActivityNotFoundException;
25 import android.content.ComponentName;
26 import android.content.Context;
27 import android.content.Intent;
28 import android.content.IntentSender;
29 import android.content.pm.LauncherActivityInfo;
30 import android.content.pm.LauncherApps;
31 import android.content.pm.PackageManager;
32 import android.graphics.drawable.Drawable;
33 import android.os.Build;
34 import android.os.Process;
35 import android.os.UserHandle;
36 import android.util.Log;
37 import android.widget.Toast;
38 
39 import androidx.annotation.Nullable;
40 
41 import com.android.launcher3.LauncherSettings;
42 import com.android.launcher3.R;
43 import com.android.launcher3.icons.ComponentWithLabelAndIcon;
44 import com.android.launcher3.icons.IconCache;
45 import com.android.launcher3.model.data.WorkspaceItemInfo;
46 import com.android.launcher3.util.PackageUserKey;
47 
48 import java.util.ArrayList;
49 import java.util.Collections;
50 import java.util.List;
51 
52 /**
53  * Wrapper class for representing a shortcut configure activity.
54  */
55 public abstract class ShortcutConfigActivityInfo implements ComponentWithLabelAndIcon {
56 
57     private static final String TAG = "SCActivityInfo";
58 
59     private final ComponentName mCn;
60     private final UserHandle mUser;
61 
ShortcutConfigActivityInfo(ComponentName cn, UserHandle user)62     protected ShortcutConfigActivityInfo(ComponentName cn, UserHandle user) {
63         mCn = cn;
64         mUser = user;
65     }
66 
67     @Override
getComponent()68     public ComponentName getComponent() {
69         return mCn;
70     }
71 
72     @Override
getUser()73     public UserHandle getUser() {
74         return mUser;
75     }
76 
getItemType()77     public int getItemType() {
78         return LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
79     }
80 
81     @Override
getFullResIcon(IconCache cache)82     public abstract Drawable getFullResIcon(IconCache cache);
83 
84     /**
85      * Return a WorkspaceItemInfo, if it can be created directly on drop, without requiring any
86      * {@link #startConfigActivity(Activity, int)}.
87      */
createWorkspaceItemInfo()88     public WorkspaceItemInfo createWorkspaceItemInfo() {
89         return null;
90     }
91 
startConfigActivity(Activity activity, int requestCode)92     public boolean startConfigActivity(Activity activity, int requestCode) {
93         Intent intent = new Intent(Intent.ACTION_CREATE_SHORTCUT)
94                 .setComponent(getComponent());
95         try {
96             activity.startActivityForResult(intent, requestCode);
97             return true;
98         } catch (ActivityNotFoundException e) {
99             Toast.makeText(activity, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
100         } catch (SecurityException e) {
101             Toast.makeText(activity, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
102             Log.e(TAG, "Launcher does not have the permission to launch " + intent
103                     + ". Make sure to create a MAIN intent-filter for the corresponding activity "
104                     + "or use the exported attribute for this activity.", e);
105         }
106         return false;
107     }
108 
109     /**
110      * Returns true if various properties ({@link #getLabel(PackageManager)},
111      * {@link #getFullResIcon}) can be safely persisted.
112      */
isPersistable()113     public boolean isPersistable() {
114         return true;
115     }
116 
117     @TargetApi(26)
118     public static class ShortcutConfigActivityInfoVO extends ShortcutConfigActivityInfo {
119 
120         private final LauncherActivityInfo mInfo;
121 
ShortcutConfigActivityInfoVO(LauncherActivityInfo info)122         public ShortcutConfigActivityInfoVO(LauncherActivityInfo info) {
123             super(info.getComponentName(), info.getUser());
124             mInfo = info;
125         }
126 
127         @Override
getLabel(PackageManager pm)128         public CharSequence getLabel(PackageManager pm) {
129             return mInfo.getLabel();
130         }
131 
132         @Override
getFullResIcon(IconCache cache)133         public Drawable getFullResIcon(IconCache cache) {
134             return cache.getFullResIcon(mInfo);
135         }
136 
137         @Override
startConfigActivity(Activity activity, int requestCode)138         public boolean startConfigActivity(Activity activity, int requestCode) {
139             if (getUser().equals(Process.myUserHandle())) {
140                 return super.startConfigActivity(activity, requestCode);
141             }
142             IntentSender is = activity.getSystemService(LauncherApps.class)
143                     .getShortcutConfigActivityIntent(mInfo);
144             ActivityOptions options = allowBGLaunch(ActivityOptions.makeBasic());
145             try {
146                 activity.startIntentSenderForResult(is, requestCode, null, 0, 0, 0,
147                         options.toBundle());
148                 return true;
149             } catch (IntentSender.SendIntentException e) {
150                 Toast.makeText(activity, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
151                 return false;
152             }
153         }
154     }
155 
queryList( Context context, @Nullable PackageUserKey packageUser)156     public static List<ShortcutConfigActivityInfo> queryList(
157             Context context, @Nullable PackageUserKey packageUser) {
158         List<ShortcutConfigActivityInfo> result = new ArrayList<>();
159         final List<UserHandle> users;
160         final String packageName;
161         if (packageUser == null) {
162             users = UserCache.INSTANCE.get(context).getUserProfiles();
163             packageName = null;
164         } else {
165             users = Collections.singletonList(packageUser.mUser);
166             packageName = packageUser.mPackageName;
167         }
168         LauncherApps launcherApps = context.getSystemService(LauncherApps.class);
169         for (UserHandle user : users) {
170             for (LauncherActivityInfo activityInfo :
171                     launcherApps.getShortcutConfigActivityList(packageName, user)) {
172                 if (activityInfo.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.O) {
173                     result.add(new ShortcutConfigActivityInfoVO(activityInfo));
174                 }
175             }
176         }
177         return result;
178     }
179 }
180