InstallShortcutReceiver.java revision 82b016cb56540fe26213e817dd0dd668099c8e20
131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project/* 231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project 331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * you may not use this file except in compliance with the License. 631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * You may obtain a copy of the License at 731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 1031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 1131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 1231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * See the License for the specific language governing permissions and 1431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * limitations under the License. 1531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 1631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 17325dc23624160689e59fbac708cf6f222b20d025Daniel Sandlerpackage com.android.launcher3; 1831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 1931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.content.BroadcastReceiver; 2031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.content.Context; 2131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.content.Intent; 22f0c6ae0e35d3e020db55b5b826955da66b14b7f6Winson Chungimport android.content.SharedPreferences; 23c3a747ac245d6175a6838230d8b01c618555e062Winson Chungimport android.content.pm.ActivityInfo; 24c3a747ac245d6175a6838230d8b01c618555e062Winson Chungimport android.content.pm.PackageManager; 250b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyalimport android.content.pm.ResolveInfo; 2648c7a93eb7ef15ef551aee80c179b8e7e0d2399aMichael Jurkaimport android.graphics.Bitmap; 2748c7a93eb7ef15ef551aee80c179b8e7e0d2399aMichael Jurkaimport android.graphics.BitmapFactory; 28dff0bfeb901e767ca9b57f9b8051c7fd077626e9Nilesh Agrawalimport android.text.TextUtils; 2948c7a93eb7ef15ef551aee80c179b8e7e0d2399aMichael Jurkaimport android.util.Base64; 3048c7a93eb7ef15ef551aee80c179b8e7e0d2399aMichael Jurkaimport android.util.Log; 3131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 32e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyalimport com.android.launcher3.compat.LauncherActivityInfoCompat; 33e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyalimport com.android.launcher3.compat.LauncherAppsCompat; 34a28b78e8385f0f590b144038157afc7d34cd48b7Adam Cohenimport com.android.launcher3.compat.UserHandleCompat; 35e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyalimport com.android.launcher3.compat.UserManagerCompat; 36091440a9cb9d4f42406631004aa484cbb79214caAdam Cohenimport com.android.launcher3.util.Thunk; 37a28b78e8385f0f590b144038157afc7d34cd48b7Adam Cohen 38e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyalimport org.json.JSONException; 3934c2e6cf7af328aba25c98158161dbad15ae986dMichael Jurkaimport org.json.JSONObject; 4034c2e6cf7af328aba25c98158161dbad15ae986dMichael Jurkaimport org.json.JSONStringer; 4134c2e6cf7af328aba25c98158161dbad15ae986dMichael Jurkaimport org.json.JSONTokener; 4234c2e6cf7af328aba25c98158161dbad15ae986dMichael Jurka 43e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyalimport java.net.URISyntaxException; 44e428e292c27e650ab4de76b78728ba55019cd282Winson Chungimport java.util.ArrayList; 45f0c6ae0e35d3e020db55b5b826955da66b14b7f6Winson Chungimport java.util.HashSet; 46f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chungimport java.util.Iterator; 47f0c6ae0e35d3e020db55b5b826955da66b14b7f6Winson Chungimport java.util.Set; 48e428e292c27e650ab4de76b78728ba55019cd282Winson Chung 4931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectpublic class InstallShortcutReceiver extends BroadcastReceiver { 504e871a217b286775dc6c07feb6d9f1d7a7e914beBjorn Bringert private static final String TAG = "InstallShortcutReceiver"; 514e871a217b286775dc6c07feb6d9f1d7a7e914beBjorn Bringert private static final boolean DBG = false; 524e871a217b286775dc6c07feb6d9f1d7a7e914beBjorn Bringert 532350bc97851eea1662eee43d61290eb7a8382021Sunny Goyal private static final String ACTION_INSTALL_SHORTCUT = 5494d6768c65929efa21bb893fdef7f269d65da3c3Winson Chung "com.android.launcher.action.INSTALL_SHORTCUT"; 55f0c6ae0e35d3e020db55b5b826955da66b14b7f6Winson Chung 562350bc97851eea1662eee43d61290eb7a8382021Sunny Goyal private static final String LAUNCH_INTENT_KEY = "intent.launch"; 572350bc97851eea1662eee43d61290eb7a8382021Sunny Goyal private static final String NAME_KEY = "name"; 582350bc97851eea1662eee43d61290eb7a8382021Sunny Goyal private static final String ICON_KEY = "icon"; 592350bc97851eea1662eee43d61290eb7a8382021Sunny Goyal private static final String ICON_RESOURCE_NAME_KEY = "iconResource"; 602350bc97851eea1662eee43d61290eb7a8382021Sunny Goyal private static final String ICON_RESOURCE_PACKAGE_NAME_KEY = "iconResourcePackage"; 61e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal 62e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal private static final String APP_SHORTCUT_TYPE_KEY = "isAppShortcut"; 63e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal private static final String USER_HANDLE_KEY = "userHandle"; 64e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal 6548c7a93eb7ef15ef551aee80c179b8e7e0d2399aMichael Jurka // The set of shortcuts that are pending install 662350bc97851eea1662eee43d61290eb7a8382021Sunny Goyal private static final String APPS_PENDING_INSTALL = "apps_to_install"; 6748c7a93eb7ef15ef551aee80c179b8e7e0d2399aMichael Jurka 68f0c6ae0e35d3e020db55b5b826955da66b14b7f6Winson Chung public static final int NEW_SHORTCUT_BOUNCE_DURATION = 450; 69997a92348a6d6e061737399321393449c16cd4d8Winson Chung public static final int NEW_SHORTCUT_STAGGER_DELAY = 85; 70f0c6ae0e35d3e020db55b5b826955da66b14b7f6Winson Chung 71e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal private static final Object sLock = new Object(); 7248c7a93eb7ef15ef551aee80c179b8e7e0d2399aMichael Jurka 7348c7a93eb7ef15ef551aee80c179b8e7e0d2399aMichael Jurka private static void addToInstallQueue( 7448c7a93eb7ef15ef551aee80c179b8e7e0d2399aMichael Jurka SharedPreferences sharedPrefs, PendingInstallShortcutInfo info) { 7548c7a93eb7ef15ef551aee80c179b8e7e0d2399aMichael Jurka synchronized(sLock) { 76e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal String encoded = info.encodeToString(); 77e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal if (encoded != null) { 78e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal Set<String> strings = sharedPrefs.getStringSet(APPS_PENDING_INSTALL, null); 79e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal if (strings == null) { 80e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal strings = new HashSet<String>(1); 81e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal } else { 82e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal strings = new HashSet<String>(strings); 8348c7a93eb7ef15ef551aee80c179b8e7e0d2399aMichael Jurka } 84e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal strings.add(encoded); 85e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal sharedPrefs.edit().putStringSet(APPS_PENDING_INSTALL, strings).commit(); 8648c7a93eb7ef15ef551aee80c179b8e7e0d2399aMichael Jurka } 8748c7a93eb7ef15ef551aee80c179b8e7e0d2399aMichael Jurka } 8848c7a93eb7ef15ef551aee80c179b8e7e0d2399aMichael Jurka } 8948c7a93eb7ef15ef551aee80c179b8e7e0d2399aMichael Jurka 90e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal public static void removeFromInstallQueue(Context context, ArrayList<String> packageNames, 91e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal UserHandleCompat user) { 92df95eb12a4d288ffa143a0c3db60e7e98f3e03b9Winson Chung if (packageNames.isEmpty()) { 93df95eb12a4d288ffa143a0c3db60e7e98f3e03b9Winson Chung return; 94df95eb12a4d288ffa143a0c3db60e7e98f3e03b9Winson Chung } 95e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal String spKey = LauncherAppState.getSharedPreferencesKey(); 96e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal SharedPreferences sp = context.getSharedPreferences(spKey, Context.MODE_PRIVATE); 97780fe59a7af8b12fbdcd7f6841edaa7f2c2e019dWinson Chung synchronized(sLock) { 98e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal Set<String> strings = sp.getStringSet(APPS_PENDING_INSTALL, null); 994e871a217b286775dc6c07feb6d9f1d7a7e914beBjorn Bringert if (DBG) { 1004e871a217b286775dc6c07feb6d9f1d7a7e914beBjorn Bringert Log.d(TAG, "APPS_PENDING_INSTALL: " + strings 1014e871a217b286775dc6c07feb6d9f1d7a7e914beBjorn Bringert + ", removing packages: " + packageNames); 1024e871a217b286775dc6c07feb6d9f1d7a7e914beBjorn Bringert } 103780fe59a7af8b12fbdcd7f6841edaa7f2c2e019dWinson Chung if (strings != null) { 104780fe59a7af8b12fbdcd7f6841edaa7f2c2e019dWinson Chung Set<String> newStrings = new HashSet<String>(strings); 1054e871a217b286775dc6c07feb6d9f1d7a7e914beBjorn Bringert Iterator<String> newStringsIter = newStrings.iterator(); 1064e871a217b286775dc6c07feb6d9f1d7a7e914beBjorn Bringert while (newStringsIter.hasNext()) { 107e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal String encoded = newStringsIter.next(); 108e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal PendingInstallShortcutInfo info = decode(encoded, context); 109e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal if (info == null || (packageNames.contains(info.getTargetPackage()) 110e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal && user.equals(info.user))) { 111e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal newStringsIter.remove(); 112780fe59a7af8b12fbdcd7f6841edaa7f2c2e019dWinson Chung } 113780fe59a7af8b12fbdcd7f6841edaa7f2c2e019dWinson Chung } 114e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal sp.edit().putStringSet(APPS_PENDING_INSTALL, newStrings).commit(); 115780fe59a7af8b12fbdcd7f6841edaa7f2c2e019dWinson Chung } 116780fe59a7af8b12fbdcd7f6841edaa7f2c2e019dWinson Chung } 117780fe59a7af8b12fbdcd7f6841edaa7f2c2e019dWinson Chung } 118780fe59a7af8b12fbdcd7f6841edaa7f2c2e019dWinson Chung 11948c7a93eb7ef15ef551aee80c179b8e7e0d2399aMichael Jurka private static ArrayList<PendingInstallShortcutInfo> getAndClearInstallQueue( 120e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal SharedPreferences sharedPrefs, Context context) { 12148c7a93eb7ef15ef551aee80c179b8e7e0d2399aMichael Jurka synchronized(sLock) { 12248c7a93eb7ef15ef551aee80c179b8e7e0d2399aMichael Jurka Set<String> strings = sharedPrefs.getStringSet(APPS_PENDING_INSTALL, null); 1234e871a217b286775dc6c07feb6d9f1d7a7e914beBjorn Bringert if (DBG) Log.d(TAG, "Getting and clearing APPS_PENDING_INSTALL: " + strings); 12448c7a93eb7ef15ef551aee80c179b8e7e0d2399aMichael Jurka if (strings == null) { 12548c7a93eb7ef15ef551aee80c179b8e7e0d2399aMichael Jurka return new ArrayList<PendingInstallShortcutInfo>(); 12648c7a93eb7ef15ef551aee80c179b8e7e0d2399aMichael Jurka } 12748c7a93eb7ef15ef551aee80c179b8e7e0d2399aMichael Jurka ArrayList<PendingInstallShortcutInfo> infos = 12848c7a93eb7ef15ef551aee80c179b8e7e0d2399aMichael Jurka new ArrayList<PendingInstallShortcutInfo>(); 129e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal for (String encoded : strings) { 130e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal PendingInstallShortcutInfo info = decode(encoded, context); 131e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal if (info != null) { 13248c7a93eb7ef15ef551aee80c179b8e7e0d2399aMichael Jurka infos.add(info); 13348c7a93eb7ef15ef551aee80c179b8e7e0d2399aMichael Jurka } 13448c7a93eb7ef15ef551aee80c179b8e7e0d2399aMichael Jurka } 13548c7a93eb7ef15ef551aee80c179b8e7e0d2399aMichael Jurka sharedPrefs.edit().putStringSet(APPS_PENDING_INSTALL, new HashSet<String>()).commit(); 13648c7a93eb7ef15ef551aee80c179b8e7e0d2399aMichael Jurka return infos; 13748c7a93eb7ef15ef551aee80c179b8e7e0d2399aMichael Jurka } 13848c7a93eb7ef15ef551aee80c179b8e7e0d2399aMichael Jurka } 13948c7a93eb7ef15ef551aee80c179b8e7e0d2399aMichael Jurka 140f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung // Determines whether to defer installing shortcuts immediately until 141f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung // processAllPendingInstalls() is called. 142f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung private static boolean mUseInstallQueue = false; 143f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung 14431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public void onReceive(Context context, Intent data) { 14551ed5b9bc05c6eb37dcb3fe38fa021f1044c0f88Romain Guy if (!ACTION_INSTALL_SHORTCUT.equals(data.getAction())) { 14651ed5b9bc05c6eb37dcb3fe38fa021f1044c0f88Romain Guy return; 14751ed5b9bc05c6eb37dcb3fe38fa021f1044c0f88Romain Guy } 14851ed5b9bc05c6eb37dcb3fe38fa021f1044c0f88Romain Guy 149e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal PendingInstallShortcutInfo info = new PendingInstallShortcutInfo(data, context); 1503290ec4cc220f97460b3b19f28adaf829ea971e1Sunny Goyal if (info.launchIntent == null || info.label == null) { 1513290ec4cc220f97460b3b19f28adaf829ea971e1Sunny Goyal if (DBG) Log.e(TAG, "Invalid install shortcut intent"); 1523290ec4cc220f97460b3b19f28adaf829ea971e1Sunny Goyal return; 1533290ec4cc220f97460b3b19f28adaf829ea971e1Sunny Goyal } 1544e871a217b286775dc6c07feb6d9f1d7a7e914beBjorn Bringert 1553290ec4cc220f97460b3b19f28adaf829ea971e1Sunny Goyal info = convertToLauncherActivityIfPossible(info); 156e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal queuePendingShortcutInfo(info, context); 157e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal } 158dff0bfeb901e767ca9b57f9b8051c7fd077626e9Nilesh Agrawal 159e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal static void queueInstallShortcut(LauncherActivityInfoCompat info, Context context) { 160e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal queuePendingShortcutInfo(new PendingInstallShortcutInfo(info, context), context); 161e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal } 16248c7a93eb7ef15ef551aee80c179b8e7e0d2399aMichael Jurka 163e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal private static void queuePendingShortcutInfo(PendingInstallShortcutInfo info, Context context) { 164de0fb8fbf11caac382589ab464b50d528942273aWinson Chung // Queue the item up for adding if launcher has not loaded properly yet 165c88dceb0b567ab96418e73cf2f6b197ba2646cb3Winson Chung LauncherAppState.setApplicationContext(context.getApplicationContext()); 166892c74d460ad98c6306420e1127c9aa3e505ba25Winson Chung LauncherAppState app = LauncherAppState.getInstance(); 167e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal boolean launcherNotLoaded = app.getModel().getCallback() == null; 168997a92348a6d6e061737399321393449c16cd4d8Winson Chung 169997a92348a6d6e061737399321393449c16cd4d8Winson Chung String spKey = LauncherAppState.getSharedPreferencesKey(); 170997a92348a6d6e061737399321393449c16cd4d8Winson Chung SharedPreferences sp = context.getSharedPreferences(spKey, Context.MODE_PRIVATE); 171997a92348a6d6e061737399321393449c16cd4d8Winson Chung addToInstallQueue(sp, info); 172997a92348a6d6e061737399321393449c16cd4d8Winson Chung if (!mUseInstallQueue && !launcherNotLoaded) { 173997a92348a6d6e061737399321393449c16cd4d8Winson Chung flushInstallQueue(context); 174f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung } 175f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung } 176f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung 177f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung static void enableInstallQueue() { 178f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung mUseInstallQueue = true; 179f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung } 180f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung static void disableAndFlushInstallQueue(Context context) { 181f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung mUseInstallQueue = false; 182de0fb8fbf11caac382589ab464b50d528942273aWinson Chung flushInstallQueue(context); 183de0fb8fbf11caac382589ab464b50d528942273aWinson Chung } 184de0fb8fbf11caac382589ab464b50d528942273aWinson Chung static void flushInstallQueue(Context context) { 185cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler String spKey = LauncherAppState.getSharedPreferencesKey(); 18648c7a93eb7ef15ef551aee80c179b8e7e0d2399aMichael Jurka SharedPreferences sp = context.getSharedPreferences(spKey, Context.MODE_PRIVATE); 187e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal ArrayList<PendingInstallShortcutInfo> installQueue = getAndClearInstallQueue(sp, context); 188997a92348a6d6e061737399321393449c16cd4d8Winson Chung if (!installQueue.isEmpty()) { 189997a92348a6d6e061737399321393449c16cd4d8Winson Chung Iterator<PendingInstallShortcutInfo> iter = installQueue.iterator(); 190997a92348a6d6e061737399321393449c16cd4d8Winson Chung ArrayList<ItemInfo> addShortcuts = new ArrayList<ItemInfo>(); 191997a92348a6d6e061737399321393449c16cd4d8Winson Chung while (iter.hasNext()) { 192997a92348a6d6e061737399321393449c16cd4d8Winson Chung final PendingInstallShortcutInfo pendingInfo = iter.next(); 193997a92348a6d6e061737399321393449c16cd4d8Winson Chung final Intent intent = pendingInfo.launchIntent; 194dff0bfeb901e767ca9b57f9b8051c7fd077626e9Nilesh Agrawal 195a28b78e8385f0f590b144038157afc7d34cd48b7Adam Cohen // If the intent specifies a package, make sure the package exists 196e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal String packageName = pendingInfo.getTargetPackage(); 197f2048779990bfd3c20b52149f5e8ab208bf2502aSunny Goyal if (!TextUtils.isEmpty(packageName)) { 198a28b78e8385f0f590b144038157afc7d34cd48b7Adam Cohen UserHandleCompat myUserHandle = UserHandleCompat.myUserHandle(); 199a28b78e8385f0f590b144038157afc7d34cd48b7Adam Cohen if (!LauncherModel.isValidPackage(context, packageName, myUserHandle)) { 200a28b78e8385f0f590b144038157afc7d34cd48b7Adam Cohen if (DBG) Log.d(TAG, "Ignoring shortcut for absent package:" + intent); 201a28b78e8385f0f590b144038157afc7d34cd48b7Adam Cohen continue; 202a28b78e8385f0f590b144038157afc7d34cd48b7Adam Cohen } 203a28b78e8385f0f590b144038157afc7d34cd48b7Adam Cohen } 204a28b78e8385f0f590b144038157afc7d34cd48b7Adam Cohen 205756adbc3e41ee1edb53c580b8c679f343924fab5Sunny Goyal // Generate a shortcut info to add into the model 206756adbc3e41ee1edb53c580b8c679f343924fab5Sunny Goyal addShortcuts.add(pendingInfo.getShortcutInfo()); 207f0c6ae0e35d3e020db55b5b826955da66b14b7f6Winson Chung } 208f0c6ae0e35d3e020db55b5b826955da66b14b7f6Winson Chung 209997a92348a6d6e061737399321393449c16cd4d8Winson Chung // Add the new apps to the model and bind them 210997a92348a6d6e061737399321393449c16cd4d8Winson Chung if (!addShortcuts.isEmpty()) { 211997a92348a6d6e061737399321393449c16cd4d8Winson Chung LauncherAppState app = LauncherAppState.getInstance(); 21218bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal app.getModel().addAndBindAddedWorkspaceItems(context, addShortcuts); 21331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 21431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 21531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 21631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 217dff0bfeb901e767ca9b57f9b8051c7fd077626e9Nilesh Agrawal /** 218dff0bfeb901e767ca9b57f9b8051c7fd077626e9Nilesh Agrawal * Returns true if the intent is a valid launch intent for a shortcut. 219dff0bfeb901e767ca9b57f9b8051c7fd077626e9Nilesh Agrawal * This is used to identify shortcuts which are different from the ones exposed by the 220dff0bfeb901e767ca9b57f9b8051c7fd077626e9Nilesh Agrawal * applications' manifest file. 221dff0bfeb901e767ca9b57f9b8051c7fd077626e9Nilesh Agrawal * 222dff0bfeb901e767ca9b57f9b8051c7fd077626e9Nilesh Agrawal * When DISABLE_ALL_APPS is true, shortcuts exposed via the app's manifest should never be 223dff0bfeb901e767ca9b57f9b8051c7fd077626e9Nilesh Agrawal * duplicated or removed(unless the app is un-installed). 224dff0bfeb901e767ca9b57f9b8051c7fd077626e9Nilesh Agrawal * 225dff0bfeb901e767ca9b57f9b8051c7fd077626e9Nilesh Agrawal * @param launchIntent The intent that will be launched when the shortcut is clicked. 226dff0bfeb901e767ca9b57f9b8051c7fd077626e9Nilesh Agrawal */ 227dff0bfeb901e767ca9b57f9b8051c7fd077626e9Nilesh Agrawal static boolean isValidShortcutLaunchIntent(Intent launchIntent) { 228dff0bfeb901e767ca9b57f9b8051c7fd077626e9Nilesh Agrawal if (launchIntent != null 229dff0bfeb901e767ca9b57f9b8051c7fd077626e9Nilesh Agrawal && Intent.ACTION_MAIN.equals(launchIntent.getAction()) 230dff0bfeb901e767ca9b57f9b8051c7fd077626e9Nilesh Agrawal && launchIntent.getComponent() != null 231dff0bfeb901e767ca9b57f9b8051c7fd077626e9Nilesh Agrawal && launchIntent.getCategories() != null 232dff0bfeb901e767ca9b57f9b8051c7fd077626e9Nilesh Agrawal && launchIntent.getCategories().size() == 1 233dff0bfeb901e767ca9b57f9b8051c7fd077626e9Nilesh Agrawal && launchIntent.hasCategory(Intent.CATEGORY_LAUNCHER) 234dff0bfeb901e767ca9b57f9b8051c7fd077626e9Nilesh Agrawal && launchIntent.getExtras() == null 235dff0bfeb901e767ca9b57f9b8051c7fd077626e9Nilesh Agrawal && TextUtils.isEmpty(launchIntent.getDataString())) { 236dff0bfeb901e767ca9b57f9b8051c7fd077626e9Nilesh Agrawal return false; 237dff0bfeb901e767ca9b57f9b8051c7fd077626e9Nilesh Agrawal } 238dff0bfeb901e767ca9b57f9b8051c7fd077626e9Nilesh Agrawal return true; 239dff0bfeb901e767ca9b57f9b8051c7fd077626e9Nilesh Agrawal } 240dff0bfeb901e767ca9b57f9b8051c7fd077626e9Nilesh Agrawal 2412c1afde5cd60eb13f05aeae0c170e697493ef307Winson Chung /** 2422c1afde5cd60eb13f05aeae0c170e697493ef307Winson Chung * Ensures that we have a valid, non-null name. If the provided name is null, we will return 2432c1afde5cd60eb13f05aeae0c170e697493ef307Winson Chung * the application name instead. 2442c1afde5cd60eb13f05aeae0c170e697493ef307Winson Chung */ 245091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen @Thunk static CharSequence ensureValidName(Context context, Intent intent, CharSequence name) { 2462c1afde5cd60eb13f05aeae0c170e697493ef307Winson Chung if (name == null) { 2472c1afde5cd60eb13f05aeae0c170e697493ef307Winson Chung try { 2482c1afde5cd60eb13f05aeae0c170e697493ef307Winson Chung PackageManager pm = context.getPackageManager(); 2492c1afde5cd60eb13f05aeae0c170e697493ef307Winson Chung ActivityInfo info = pm.getActivityInfo(intent.getComponent(), 0); 25082b016cb56540fe26213e817dd0dd668099c8e20Winson Chung name = info.loadLabel(pm); 2512c1afde5cd60eb13f05aeae0c170e697493ef307Winson Chung } catch (PackageManager.NameNotFoundException nnfe) { 2522c1afde5cd60eb13f05aeae0c170e697493ef307Winson Chung return ""; 2532c1afde5cd60eb13f05aeae0c170e697493ef307Winson Chung } 2542c1afde5cd60eb13f05aeae0c170e697493ef307Winson Chung } 2552c1afde5cd60eb13f05aeae0c170e697493ef307Winson Chung return name; 25631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 257e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal 258e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal private static class PendingInstallShortcutInfo { 259e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal 260e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal final LauncherActivityInfoCompat activityInfo; 261e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal 262e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal final Intent data; 263e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal final Context mContext; 264e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal final Intent launchIntent; 265e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal final String label; 266e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal final UserHandleCompat user; 267e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal 268e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal /** 269e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal * Initializes a PendingInstallShortcutInfo received from a different app. 270e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal */ 271e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal public PendingInstallShortcutInfo(Intent data, Context context) { 272e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal this.data = data; 273e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal mContext = context; 274e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal 275e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal launchIntent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT); 276e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal label = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME); 277e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal user = UserHandleCompat.myUserHandle(); 278e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal activityInfo = null; 279e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal } 280e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal 281e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal /** 282e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal * Initializes a PendingInstallShortcutInfo to represent a launcher target. 283e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal */ 284e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal public PendingInstallShortcutInfo(LauncherActivityInfoCompat info, Context context) { 285e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal this.data = null; 286e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal mContext = context; 287e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal activityInfo = info; 288e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal user = info.getUser(); 289e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal 290e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal launchIntent = AppInfo.makeLaunchIntent(context, info, user); 291e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal label = info.getLabel().toString(); 292e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal } 293e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal 294e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal public String encodeToString() { 295e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal if (activityInfo != null) { 296e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal try { 297e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal // If it a launcher target, we only need component name, and user to 298e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal // recreate this. 299e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal return new JSONStringer() 300e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal .object() 301e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal .key(LAUNCH_INTENT_KEY).value(launchIntent.toUri(0)) 302e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal .key(APP_SHORTCUT_TYPE_KEY).value(true) 303e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal .key(USER_HANDLE_KEY).value(UserManagerCompat.getInstance(mContext) 304e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal .getSerialNumberForUser(user)) 305e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal .endObject().toString(); 306e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal } catch (JSONException e) { 307e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal Log.d(TAG, "Exception when adding shortcut: " + e); 308e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal return null; 309e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal } 310e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal } 311e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal 312e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal if (launchIntent.getAction() == null) { 313e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal launchIntent.setAction(Intent.ACTION_VIEW); 314e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal } else if (launchIntent.getAction().equals(Intent.ACTION_MAIN) && 315e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal launchIntent.getCategories() != null && 316e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal launchIntent.getCategories().contains(Intent.CATEGORY_LAUNCHER)) { 317e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal launchIntent.addFlags( 318e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); 319e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal } 320e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal 321e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal // This name is only used for comparisons and notifications, so fall back to activity 322e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal // name if not supplied 323e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal String name = ensureValidName(mContext, launchIntent, label).toString(); 324e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal Bitmap icon = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON); 325e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal Intent.ShortcutIconResource iconResource = 326e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE); 327e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal 328e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal // Only encode the parameters which are supported by the API. 329e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal try { 330e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal JSONStringer json = new JSONStringer() 331e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal .object() 332e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal .key(LAUNCH_INTENT_KEY).value(launchIntent.toUri(0)) 333e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal .key(NAME_KEY).value(name); 334e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal if (icon != null) { 3355b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal byte[] iconByteArray = Utilities.flattenBitmap(icon); 336e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal json = json.key(ICON_KEY).value( 337e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal Base64.encodeToString( 338e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal iconByteArray, 0, iconByteArray.length, Base64.DEFAULT)); 339e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal } 340e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal if (iconResource != null) { 341e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal json = json.key(ICON_RESOURCE_NAME_KEY).value(iconResource.resourceName); 342e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal json = json.key(ICON_RESOURCE_PACKAGE_NAME_KEY) 343e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal .value(iconResource.packageName); 344e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal } 345e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal return json.endObject().toString(); 346e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal } catch (JSONException e) { 347e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal Log.d(TAG, "Exception when adding shortcut: " + e); 348e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal } 349e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal return null; 350e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal } 351e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal 352e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal public ShortcutInfo getShortcutInfo() { 353e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal if (activityInfo != null) { 35418bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal return ShortcutInfo.fromActivityInfo(activityInfo, mContext); 355e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal } else { 356e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal return LauncherAppState.getInstance().getModel().infoFromShortcutIntent(mContext, data); 357e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal } 358e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal } 359e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal 360e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal public String getTargetPackage() { 361e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal String packageName = launchIntent.getPackage(); 362e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal if (packageName == null) { 363e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal packageName = launchIntent.getComponent() == null ? null : 364e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal launchIntent.getComponent().getPackageName(); 365e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal } 366e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal return packageName; 367e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal } 3680b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal 3690b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal public boolean isLuncherActivity() { 3700b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal return activityInfo != null; 3710b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal } 372e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal } 373e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal 374e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal private static PendingInstallShortcutInfo decode(String encoded, Context context) { 375e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal try { 376e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal JSONObject object = (JSONObject) new JSONTokener(encoded).nextValue(); 377e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal Intent launcherIntent = Intent.parseUri(object.getString(LAUNCH_INTENT_KEY), 0); 378e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal 379e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal if (object.optBoolean(APP_SHORTCUT_TYPE_KEY)) { 380e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal // The is an internal launcher target shortcut. 381e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal UserHandleCompat user = UserManagerCompat.getInstance(context) 382e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal .getUserForSerialNumber(object.getLong(USER_HANDLE_KEY)); 38306910a88445c46fb95c9ad5ff83793e37b6af692Sunny Goyal if (user == null) { 38406910a88445c46fb95c9ad5ff83793e37b6af692Sunny Goyal return null; 38506910a88445c46fb95c9ad5ff83793e37b6af692Sunny Goyal } 386e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal 387e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal LauncherActivityInfoCompat info = LauncherAppsCompat.getInstance(context) 388e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal .resolveActivity(launcherIntent, user); 389e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal return info == null ? null : new PendingInstallShortcutInfo(info, context); 390e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal } 391e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal 392e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal Intent data = new Intent(); 393e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal data.putExtra(Intent.EXTRA_SHORTCUT_INTENT, launcherIntent); 394e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal data.putExtra(Intent.EXTRA_SHORTCUT_NAME, object.getString(NAME_KEY)); 395e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal 396e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal String iconBase64 = object.optString(ICON_KEY); 397e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal String iconResourceName = object.optString(ICON_RESOURCE_NAME_KEY); 398e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal String iconResourcePackageName = object.optString(ICON_RESOURCE_PACKAGE_NAME_KEY); 399e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal if (iconBase64 != null && !iconBase64.isEmpty()) { 400e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal byte[] iconArray = Base64.decode(iconBase64, Base64.DEFAULT); 401e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal Bitmap b = BitmapFactory.decodeByteArray(iconArray, 0, iconArray.length); 402e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal data.putExtra(Intent.EXTRA_SHORTCUT_ICON, b); 403e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal } else if (iconResourceName != null && !iconResourceName.isEmpty()) { 404e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal Intent.ShortcutIconResource iconResource = 405e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal new Intent.ShortcutIconResource(); 406e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal iconResource.resourceName = iconResourceName; 407e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal iconResource.packageName = iconResourcePackageName; 408e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal data.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, iconResource); 409e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal } 410e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal 411e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal return new PendingInstallShortcutInfo(data, context); 412e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal } catch (JSONException e) { 413e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal Log.d(TAG, "Exception reading shortcut to add: " + e); 414e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal } catch (URISyntaxException e) { 415e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal Log.d(TAG, "Exception reading shortcut to add: " + e); 416e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal } 417e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal return null; 418e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal } 4190b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal 4200b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal /** 4210b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal * Tries to create a new PendingInstallShortcutInfo which represents the same target, 4220b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal * but is an app target and not a shortcut. 4230b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal * @return the newly created info or the original one. 4240b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal */ 4250b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal private static PendingInstallShortcutInfo convertToLauncherActivityIfPossible( 4260b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal PendingInstallShortcutInfo original) { 4270b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal if (original.isLuncherActivity()) { 4280b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal // Already an activity target 4290b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal return original; 4300b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal } 4310b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal if (isValidShortcutLaunchIntent(original.launchIntent) 4320b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal || !original.user.equals(UserHandleCompat.myUserHandle())) { 4330b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal // We can only convert shortcuts which point to a main activity in the current user. 4340b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal return original; 4350b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal } 4360b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal 4370b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal PackageManager pm = original.mContext.getPackageManager(); 4380b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal ResolveInfo info = pm.resolveActivity(original.launchIntent, 0); 4390b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal 4400b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal if (info == null) { 4410b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal return original; 4420b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal } 4430b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal 4440b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal // Ignore any conflicts in the label name, as that can change based on locale. 4450b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal LauncherActivityInfoCompat launcherInfo = LauncherActivityInfoCompat 4460b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal .fromResolveInfo(info, original.mContext); 4470b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal return new PendingInstallShortcutInfo(launcherInfo, original.mContext); 4480b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal } 4490b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal 4500b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal public static boolean isLauncherActivity(Intent intent, Context context) { 4510b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal Intent data = new Intent().putExtra(Intent.EXTRA_SHORTCUT_INTENT, intent); 4520b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal PendingInstallShortcutInfo info = new PendingInstallShortcutInfo(data, context); 4530b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal return convertToLauncherActivityIfPossible(info).isLuncherActivity(); 4540b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal } 45531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project} 456