blob: 0c69154aadfd7da6c19fc2f8132518c58c0345fc [file] [log] [blame]
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001/*
2 * Copyright (C) 2008 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
Daniel Sandler325dc232013-06-05 22:57:57 -040017package com.android.launcher3;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080018
19import android.content.BroadcastReceiver;
20import android.content.Context;
21import android.content.Intent;
Winson Chungf0c6ae02012-03-21 16:10:31 -070022import android.content.SharedPreferences;
Winson Chungc3a747a2012-02-29 10:56:19 -080023import android.content.pm.ActivityInfo;
24import android.content.pm.PackageManager;
Sunny Goyal0b037782015-04-02 10:27:03 -070025import android.content.pm.ResolveInfo;
Michael Jurka48c7a932013-05-14 20:17:58 +020026import android.graphics.Bitmap;
27import android.graphics.BitmapFactory;
Nilesh Agrawaldff0bfe2013-12-17 15:20:50 -080028import android.text.TextUtils;
Michael Jurka48c7a932013-05-14 20:17:58 +020029import android.util.Base64;
30import android.util.Log;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080031
Sunny Goyale0f58d72014-11-10 18:05:31 -080032import com.android.launcher3.compat.LauncherActivityInfoCompat;
33import com.android.launcher3.compat.LauncherAppsCompat;
Adam Cohena28b78e2014-05-20 17:03:04 -070034import com.android.launcher3.compat.UserHandleCompat;
Sunny Goyale0f58d72014-11-10 18:05:31 -080035import com.android.launcher3.compat.UserManagerCompat;
Adam Cohen091440a2015-03-18 14:16:05 -070036import com.android.launcher3.util.Thunk;
Adam Cohena28b78e2014-05-20 17:03:04 -070037
Sunny Goyale0f58d72014-11-10 18:05:31 -080038import org.json.JSONException;
Michael Jurka34c2e6c2013-12-13 16:07:45 +010039import org.json.JSONObject;
40import org.json.JSONStringer;
41import org.json.JSONTokener;
42
Sunny Goyale0f58d72014-11-10 18:05:31 -080043import java.net.URISyntaxException;
Winson Chunge428e292012-01-10 16:20:33 -080044import java.util.ArrayList;
Winson Chungf0c6ae02012-03-21 16:10:31 -070045import java.util.HashSet;
Winson Chungf561bdf2012-05-03 11:20:19 -070046import java.util.Iterator;
Winson Chungf0c6ae02012-03-21 16:10:31 -070047import java.util.Set;
Winson Chunge428e292012-01-10 16:20:33 -080048
The Android Open Source Project31dd5032009-03-03 19:32:27 -080049public class InstallShortcutReceiver extends BroadcastReceiver {
Bjorn Bringert4e871a22013-10-17 13:50:20 +010050 private static final String TAG = "InstallShortcutReceiver";
51 private static final boolean DBG = false;
52
Sunny Goyal2350bc92014-10-14 16:42:54 -070053 private static final String ACTION_INSTALL_SHORTCUT =
Winson Chung94d67682013-09-25 16:29:40 -070054 "com.android.launcher.action.INSTALL_SHORTCUT";
Winson Chungf0c6ae02012-03-21 16:10:31 -070055
Sunny Goyal2350bc92014-10-14 16:42:54 -070056 private static final String LAUNCH_INTENT_KEY = "intent.launch";
57 private static final String NAME_KEY = "name";
58 private static final String ICON_KEY = "icon";
59 private static final String ICON_RESOURCE_NAME_KEY = "iconResource";
60 private static final String ICON_RESOURCE_PACKAGE_NAME_KEY = "iconResourcePackage";
Sunny Goyale0f58d72014-11-10 18:05:31 -080061
62 private static final String APP_SHORTCUT_TYPE_KEY = "isAppShortcut";
63 private static final String USER_HANDLE_KEY = "userHandle";
64
Michael Jurka48c7a932013-05-14 20:17:58 +020065 // The set of shortcuts that are pending install
Sunny Goyal2350bc92014-10-14 16:42:54 -070066 private static final String APPS_PENDING_INSTALL = "apps_to_install";
Michael Jurka48c7a932013-05-14 20:17:58 +020067
Winson Chungf0c6ae02012-03-21 16:10:31 -070068 public static final int NEW_SHORTCUT_BOUNCE_DURATION = 450;
Winson Chung997a9232013-07-24 15:33:46 -070069 public static final int NEW_SHORTCUT_STAGGER_DELAY = 85;
Winson Chungf0c6ae02012-03-21 16:10:31 -070070
Sunny Goyale0f58d72014-11-10 18:05:31 -080071 private static final Object sLock = new Object();
Michael Jurka48c7a932013-05-14 20:17:58 +020072
73 private static void addToInstallQueue(
74 SharedPreferences sharedPrefs, PendingInstallShortcutInfo info) {
75 synchronized(sLock) {
Sunny Goyale0f58d72014-11-10 18:05:31 -080076 String encoded = info.encodeToString();
77 if (encoded != null) {
78 Set<String> strings = sharedPrefs.getStringSet(APPS_PENDING_INSTALL, null);
79 if (strings == null) {
80 strings = new HashSet<String>(1);
81 } else {
82 strings = new HashSet<String>(strings);
Michael Jurka48c7a932013-05-14 20:17:58 +020083 }
Sunny Goyale0f58d72014-11-10 18:05:31 -080084 strings.add(encoded);
85 sharedPrefs.edit().putStringSet(APPS_PENDING_INSTALL, strings).commit();
Michael Jurka48c7a932013-05-14 20:17:58 +020086 }
87 }
88 }
89
Sunny Goyale0f58d72014-11-10 18:05:31 -080090 public static void removeFromInstallQueue(Context context, ArrayList<String> packageNames,
91 UserHandleCompat user) {
Winson Chungdf95eb12013-10-16 14:57:07 -070092 if (packageNames.isEmpty()) {
93 return;
94 }
Sunny Goyale0f58d72014-11-10 18:05:31 -080095 String spKey = LauncherAppState.getSharedPreferencesKey();
96 SharedPreferences sp = context.getSharedPreferences(spKey, Context.MODE_PRIVATE);
Winson Chung780fe592013-09-26 14:48:44 -070097 synchronized(sLock) {
Sunny Goyale0f58d72014-11-10 18:05:31 -080098 Set<String> strings = sp.getStringSet(APPS_PENDING_INSTALL, null);
Bjorn Bringert4e871a22013-10-17 13:50:20 +010099 if (DBG) {
100 Log.d(TAG, "APPS_PENDING_INSTALL: " + strings
101 + ", removing packages: " + packageNames);
102 }
Winson Chung780fe592013-09-26 14:48:44 -0700103 if (strings != null) {
104 Set<String> newStrings = new HashSet<String>(strings);
Bjorn Bringert4e871a22013-10-17 13:50:20 +0100105 Iterator<String> newStringsIter = newStrings.iterator();
106 while (newStringsIter.hasNext()) {
Sunny Goyale0f58d72014-11-10 18:05:31 -0800107 String encoded = newStringsIter.next();
108 PendingInstallShortcutInfo info = decode(encoded, context);
109 if (info == null || (packageNames.contains(info.getTargetPackage())
110 && user.equals(info.user))) {
111 newStringsIter.remove();
Winson Chung780fe592013-09-26 14:48:44 -0700112 }
113 }
Sunny Goyale0f58d72014-11-10 18:05:31 -0800114 sp.edit().putStringSet(APPS_PENDING_INSTALL, newStrings).commit();
Winson Chung780fe592013-09-26 14:48:44 -0700115 }
116 }
117 }
118
Michael Jurka48c7a932013-05-14 20:17:58 +0200119 private static ArrayList<PendingInstallShortcutInfo> getAndClearInstallQueue(
Sunny Goyale0f58d72014-11-10 18:05:31 -0800120 SharedPreferences sharedPrefs, Context context) {
Michael Jurka48c7a932013-05-14 20:17:58 +0200121 synchronized(sLock) {
122 Set<String> strings = sharedPrefs.getStringSet(APPS_PENDING_INSTALL, null);
Bjorn Bringert4e871a22013-10-17 13:50:20 +0100123 if (DBG) Log.d(TAG, "Getting and clearing APPS_PENDING_INSTALL: " + strings);
Michael Jurka48c7a932013-05-14 20:17:58 +0200124 if (strings == null) {
125 return new ArrayList<PendingInstallShortcutInfo>();
126 }
127 ArrayList<PendingInstallShortcutInfo> infos =
128 new ArrayList<PendingInstallShortcutInfo>();
Sunny Goyale0f58d72014-11-10 18:05:31 -0800129 for (String encoded : strings) {
130 PendingInstallShortcutInfo info = decode(encoded, context);
131 if (info != null) {
Michael Jurka48c7a932013-05-14 20:17:58 +0200132 infos.add(info);
Michael Jurka48c7a932013-05-14 20:17:58 +0200133 }
134 }
135 sharedPrefs.edit().putStringSet(APPS_PENDING_INSTALL, new HashSet<String>()).commit();
136 return infos;
137 }
138 }
139
Winson Chungf561bdf2012-05-03 11:20:19 -0700140 // Determines whether to defer installing shortcuts immediately until
141 // processAllPendingInstalls() is called.
142 private static boolean mUseInstallQueue = false;
143
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800144 public void onReceive(Context context, Intent data) {
Romain Guy51ed5b92009-06-17 10:20:34 -0700145 if (!ACTION_INSTALL_SHORTCUT.equals(data.getAction())) {
146 return;
147 }
148
Bjorn Bringert4e871a22013-10-17 13:50:20 +0100149 if (DBG) Log.d(TAG, "Got INSTALL_SHORTCUT: " + data.toUri(0));
Sunny Goyale0f58d72014-11-10 18:05:31 -0800150 PendingInstallShortcutInfo info = new PendingInstallShortcutInfo(data, context);
Sunny Goyal0b037782015-04-02 10:27:03 -0700151 info = convertToLauncherActivityIfPossible(info);
Bjorn Bringert4e871a22013-10-17 13:50:20 +0100152
Sunny Goyale0f58d72014-11-10 18:05:31 -0800153 queuePendingShortcutInfo(info, context);
154 }
Nilesh Agrawaldff0bfe2013-12-17 15:20:50 -0800155
Sunny Goyale0f58d72014-11-10 18:05:31 -0800156 static void queueInstallShortcut(LauncherActivityInfoCompat info, Context context) {
157 queuePendingShortcutInfo(new PendingInstallShortcutInfo(info, context), context);
158 }
Michael Jurka48c7a932013-05-14 20:17:58 +0200159
Sunny Goyale0f58d72014-11-10 18:05:31 -0800160 private static void queuePendingShortcutInfo(PendingInstallShortcutInfo info, Context context) {
Winson Chungde0fb8f2012-05-08 14:37:08 -0700161 // Queue the item up for adding if launcher has not loaded properly yet
Winson Chungc88dceb2013-09-27 14:59:38 -0700162 LauncherAppState.setApplicationContext(context.getApplicationContext());
Winson Chung892c74d2013-08-22 16:15:50 -0700163 LauncherAppState app = LauncherAppState.getInstance();
Sunny Goyale0f58d72014-11-10 18:05:31 -0800164 boolean launcherNotLoaded = app.getModel().getCallback() == null;
Winson Chung997a9232013-07-24 15:33:46 -0700165
166 String spKey = LauncherAppState.getSharedPreferencesKey();
167 SharedPreferences sp = context.getSharedPreferences(spKey, Context.MODE_PRIVATE);
168 addToInstallQueue(sp, info);
169 if (!mUseInstallQueue && !launcherNotLoaded) {
170 flushInstallQueue(context);
Winson Chungf561bdf2012-05-03 11:20:19 -0700171 }
172 }
173
174 static void enableInstallQueue() {
175 mUseInstallQueue = true;
176 }
Winson Chungf561bdf2012-05-03 11:20:19 -0700177 static void disableAndFlushInstallQueue(Context context) {
178 mUseInstallQueue = false;
Winson Chungde0fb8f2012-05-08 14:37:08 -0700179 flushInstallQueue(context);
180 }
181 static void flushInstallQueue(Context context) {
Daniel Sandlercc8befa2013-06-11 14:45:48 -0400182 String spKey = LauncherAppState.getSharedPreferencesKey();
Michael Jurka48c7a932013-05-14 20:17:58 +0200183 SharedPreferences sp = context.getSharedPreferences(spKey, Context.MODE_PRIVATE);
Sunny Goyale0f58d72014-11-10 18:05:31 -0800184 ArrayList<PendingInstallShortcutInfo> installQueue = getAndClearInstallQueue(sp, context);
Winson Chung997a9232013-07-24 15:33:46 -0700185 if (!installQueue.isEmpty()) {
186 Iterator<PendingInstallShortcutInfo> iter = installQueue.iterator();
187 ArrayList<ItemInfo> addShortcuts = new ArrayList<ItemInfo>();
Winson Chung997a9232013-07-24 15:33:46 -0700188 while (iter.hasNext()) {
189 final PendingInstallShortcutInfo pendingInfo = iter.next();
Winson Chung997a9232013-07-24 15:33:46 -0700190 final Intent intent = pendingInfo.launchIntent;
Nilesh Agrawaldff0bfe2013-12-17 15:20:50 -0800191
Adam Cohena28b78e2014-05-20 17:03:04 -0700192 // If the intent specifies a package, make sure the package exists
Sunny Goyale0f58d72014-11-10 18:05:31 -0800193 String packageName = pendingInfo.getTargetPackage();
Sunny Goyalf2048772014-12-03 14:25:16 +0530194 if (!TextUtils.isEmpty(packageName)) {
Adam Cohena28b78e2014-05-20 17:03:04 -0700195 UserHandleCompat myUserHandle = UserHandleCompat.myUserHandle();
196 if (!LauncherModel.isValidPackage(context, packageName, myUserHandle)) {
197 if (DBG) Log.d(TAG, "Ignoring shortcut for absent package:" + intent);
198 continue;
199 }
200 }
201
Sunny Goyale0f58d72014-11-10 18:05:31 -0800202 final boolean exists = LauncherModel.shortcutExists(context, pendingInfo.label,
203 intent, pendingInfo.user);
Adam Cohena28b78e2014-05-20 17:03:04 -0700204 if (!exists) {
Winson Chung997a9232013-07-24 15:33:46 -0700205 // Generate a shortcut info to add into the model
Sunny Goyale0f58d72014-11-10 18:05:31 -0800206 addShortcuts.add(pendingInfo.getShortcutInfo());
Winson Chung997a9232013-07-24 15:33:46 -0700207 }
Winson Chung997a9232013-07-24 15:33:46 -0700208 }
209
210 // Add the new apps to the model and bind them
211 if (!addShortcuts.isEmpty()) {
212 LauncherAppState app = LauncherAppState.getInstance();
Sunny Goyal18bf8e22015-04-08 18:13:46 -0700213 app.getModel().addAndBindAddedWorkspaceItems(context, addShortcuts);
Winson Chung997a9232013-07-24 15:33:46 -0700214 }
Winson Chungf561bdf2012-05-03 11:20:19 -0700215 }
216 }
217
Nilesh Agrawaldff0bfe2013-12-17 15:20:50 -0800218 /**
219 * Returns true if the intent is a valid launch intent for a shortcut.
220 * This is used to identify shortcuts which are different from the ones exposed by the
221 * applications' manifest file.
222 *
223 * When DISABLE_ALL_APPS is true, shortcuts exposed via the app's manifest should never be
224 * duplicated or removed(unless the app is un-installed).
225 *
226 * @param launchIntent The intent that will be launched when the shortcut is clicked.
227 */
228 static boolean isValidShortcutLaunchIntent(Intent launchIntent) {
229 if (launchIntent != null
230 && Intent.ACTION_MAIN.equals(launchIntent.getAction())
231 && launchIntent.getComponent() != null
232 && launchIntent.getCategories() != null
233 && launchIntent.getCategories().size() == 1
234 && launchIntent.hasCategory(Intent.CATEGORY_LAUNCHER)
235 && launchIntent.getExtras() == null
236 && TextUtils.isEmpty(launchIntent.getDataString())) {
237 return false;
238 }
239 return true;
240 }
241
Winson Chung2c1afde2013-10-17 11:03:24 -0700242 /**
243 * Ensures that we have a valid, non-null name. If the provided name is null, we will return
244 * the application name instead.
245 */
Adam Cohen091440a2015-03-18 14:16:05 -0700246 @Thunk static CharSequence ensureValidName(Context context, Intent intent, CharSequence name) {
Winson Chung2c1afde2013-10-17 11:03:24 -0700247 if (name == null) {
248 try {
249 PackageManager pm = context.getPackageManager();
250 ActivityInfo info = pm.getActivityInfo(intent.getComponent(), 0);
251 name = info.loadLabel(pm).toString();
252 } catch (PackageManager.NameNotFoundException nnfe) {
253 return "";
254 }
255 }
256 return name;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800257 }
Sunny Goyale0f58d72014-11-10 18:05:31 -0800258
259 private static class PendingInstallShortcutInfo {
260
261 final LauncherActivityInfoCompat activityInfo;
262
263 final Intent data;
264 final Context mContext;
265 final Intent launchIntent;
266 final String label;
267 final UserHandleCompat user;
268
269 /**
270 * Initializes a PendingInstallShortcutInfo received from a different app.
271 */
272 public PendingInstallShortcutInfo(Intent data, Context context) {
273 this.data = data;
274 mContext = context;
275
276 launchIntent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);
277 label = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
278 user = UserHandleCompat.myUserHandle();
279 activityInfo = null;
280 }
281
282 /**
283 * Initializes a PendingInstallShortcutInfo to represent a launcher target.
284 */
285 public PendingInstallShortcutInfo(LauncherActivityInfoCompat info, Context context) {
286 this.data = null;
287 mContext = context;
288 activityInfo = info;
289 user = info.getUser();
290
291 launchIntent = AppInfo.makeLaunchIntent(context, info, user);
292 label = info.getLabel().toString();
293 }
294
295 public String encodeToString() {
296 if (activityInfo != null) {
297 try {
298 // If it a launcher target, we only need component name, and user to
299 // recreate this.
300 return new JSONStringer()
301 .object()
302 .key(LAUNCH_INTENT_KEY).value(launchIntent.toUri(0))
303 .key(APP_SHORTCUT_TYPE_KEY).value(true)
304 .key(USER_HANDLE_KEY).value(UserManagerCompat.getInstance(mContext)
305 .getSerialNumberForUser(user))
306 .endObject().toString();
307 } catch (JSONException e) {
308 Log.d(TAG, "Exception when adding shortcut: " + e);
309 return null;
310 }
311 }
312
313 if (launchIntent.getAction() == null) {
314 launchIntent.setAction(Intent.ACTION_VIEW);
315 } else if (launchIntent.getAction().equals(Intent.ACTION_MAIN) &&
316 launchIntent.getCategories() != null &&
317 launchIntent.getCategories().contains(Intent.CATEGORY_LAUNCHER)) {
318 launchIntent.addFlags(
319 Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
320 }
321
322 // This name is only used for comparisons and notifications, so fall back to activity
323 // name if not supplied
324 String name = ensureValidName(mContext, launchIntent, label).toString();
325 Bitmap icon = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON);
326 Intent.ShortcutIconResource iconResource =
327 data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE);
328
329 // Only encode the parameters which are supported by the API.
330 try {
331 JSONStringer json = new JSONStringer()
332 .object()
333 .key(LAUNCH_INTENT_KEY).value(launchIntent.toUri(0))
334 .key(NAME_KEY).value(name);
335 if (icon != null) {
Sunny Goyal5b0e6692015-03-19 14:31:19 -0700336 byte[] iconByteArray = Utilities.flattenBitmap(icon);
Sunny Goyale0f58d72014-11-10 18:05:31 -0800337 json = json.key(ICON_KEY).value(
338 Base64.encodeToString(
339 iconByteArray, 0, iconByteArray.length, Base64.DEFAULT));
340 }
341 if (iconResource != null) {
342 json = json.key(ICON_RESOURCE_NAME_KEY).value(iconResource.resourceName);
343 json = json.key(ICON_RESOURCE_PACKAGE_NAME_KEY)
344 .value(iconResource.packageName);
345 }
346 return json.endObject().toString();
347 } catch (JSONException e) {
348 Log.d(TAG, "Exception when adding shortcut: " + e);
349 }
350 return null;
351 }
352
353 public ShortcutInfo getShortcutInfo() {
354 if (activityInfo != null) {
Sunny Goyal18bf8e22015-04-08 18:13:46 -0700355 return ShortcutInfo.fromActivityInfo(activityInfo, mContext);
Sunny Goyale0f58d72014-11-10 18:05:31 -0800356 } else {
357 return LauncherAppState.getInstance().getModel().infoFromShortcutIntent(mContext, data);
358 }
359 }
360
361 public String getTargetPackage() {
362 String packageName = launchIntent.getPackage();
363 if (packageName == null) {
364 packageName = launchIntent.getComponent() == null ? null :
365 launchIntent.getComponent().getPackageName();
366 }
367 return packageName;
368 }
Sunny Goyal0b037782015-04-02 10:27:03 -0700369
370 public boolean isLuncherActivity() {
371 return activityInfo != null;
372 }
Sunny Goyale0f58d72014-11-10 18:05:31 -0800373 }
374
375 private static PendingInstallShortcutInfo decode(String encoded, Context context) {
376 try {
377 JSONObject object = (JSONObject) new JSONTokener(encoded).nextValue();
378 Intent launcherIntent = Intent.parseUri(object.getString(LAUNCH_INTENT_KEY), 0);
379
380 if (object.optBoolean(APP_SHORTCUT_TYPE_KEY)) {
381 // The is an internal launcher target shortcut.
382 UserHandleCompat user = UserManagerCompat.getInstance(context)
383 .getUserForSerialNumber(object.getLong(USER_HANDLE_KEY));
Sunny Goyal06910a82014-11-14 10:14:18 -0800384 if (user == null) {
385 return null;
386 }
Sunny Goyale0f58d72014-11-10 18:05:31 -0800387
388 LauncherActivityInfoCompat info = LauncherAppsCompat.getInstance(context)
389 .resolveActivity(launcherIntent, user);
390 return info == null ? null : new PendingInstallShortcutInfo(info, context);
391 }
392
393 Intent data = new Intent();
394 data.putExtra(Intent.EXTRA_SHORTCUT_INTENT, launcherIntent);
395 data.putExtra(Intent.EXTRA_SHORTCUT_NAME, object.getString(NAME_KEY));
396
397 String iconBase64 = object.optString(ICON_KEY);
398 String iconResourceName = object.optString(ICON_RESOURCE_NAME_KEY);
399 String iconResourcePackageName = object.optString(ICON_RESOURCE_PACKAGE_NAME_KEY);
400 if (iconBase64 != null && !iconBase64.isEmpty()) {
401 byte[] iconArray = Base64.decode(iconBase64, Base64.DEFAULT);
402 Bitmap b = BitmapFactory.decodeByteArray(iconArray, 0, iconArray.length);
403 data.putExtra(Intent.EXTRA_SHORTCUT_ICON, b);
404 } else if (iconResourceName != null && !iconResourceName.isEmpty()) {
405 Intent.ShortcutIconResource iconResource =
406 new Intent.ShortcutIconResource();
407 iconResource.resourceName = iconResourceName;
408 iconResource.packageName = iconResourcePackageName;
409 data.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, iconResource);
410 }
411
412 return new PendingInstallShortcutInfo(data, context);
413 } catch (JSONException e) {
414 Log.d(TAG, "Exception reading shortcut to add: " + e);
415 } catch (URISyntaxException e) {
416 Log.d(TAG, "Exception reading shortcut to add: " + e);
417 }
418 return null;
419 }
Sunny Goyal0b037782015-04-02 10:27:03 -0700420
421 /**
422 * Tries to create a new PendingInstallShortcutInfo which represents the same target,
423 * but is an app target and not a shortcut.
424 * @return the newly created info or the original one.
425 */
426 private static PendingInstallShortcutInfo convertToLauncherActivityIfPossible(
427 PendingInstallShortcutInfo original) {
428 if (original.isLuncherActivity()) {
429 // Already an activity target
430 return original;
431 }
432 if (isValidShortcutLaunchIntent(original.launchIntent)
433 || !original.user.equals(UserHandleCompat.myUserHandle())) {
434 // We can only convert shortcuts which point to a main activity in the current user.
435 return original;
436 }
437
438 PackageManager pm = original.mContext.getPackageManager();
439 ResolveInfo info = pm.resolveActivity(original.launchIntent, 0);
440
441 if (info == null) {
442 return original;
443 }
444
445 // Ignore any conflicts in the label name, as that can change based on locale.
446 LauncherActivityInfoCompat launcherInfo = LauncherActivityInfoCompat
447 .fromResolveInfo(info, original.mContext);
448 return new PendingInstallShortcutInfo(launcherInfo, original.mContext);
449 }
450
451 public static boolean isLauncherActivity(Intent intent, Context context) {
452 Intent data = new Intent().putExtra(Intent.EXTRA_SHORTCUT_INTENT, intent);
453 PendingInstallShortcutInfo info = new PendingInstallShortcutInfo(data, context);
454 return convertToLauncherActivityIfPossible(info).isLuncherActivity();
455 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800456}