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; 36fb5096d07bb3bb59fd4b5db6b68613030169b4bdSunny Goyalimport com.android.launcher3.util.PackageManagerHelper; 37091440a9cb9d4f42406631004aa484cbb79214caAdam Cohenimport com.android.launcher3.util.Thunk; 38a28b78e8385f0f590b144038157afc7d34cd48b7Adam Cohen 39e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyalimport org.json.JSONException; 4034c2e6cf7af328aba25c98158161dbad15ae986dMichael Jurkaimport org.json.JSONObject; 4134c2e6cf7af328aba25c98158161dbad15ae986dMichael Jurkaimport org.json.JSONStringer; 4234c2e6cf7af328aba25c98158161dbad15ae986dMichael Jurkaimport org.json.JSONTokener; 4334c2e6cf7af328aba25c98158161dbad15ae986dMichael Jurka 44e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyalimport java.net.URISyntaxException; 45e428e292c27e650ab4de76b78728ba55019cd282Winson Chungimport java.util.ArrayList; 46f0c6ae0e35d3e020db55b5b826955da66b14b7f6Winson Chungimport java.util.HashSet; 47f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chungimport java.util.Iterator; 48f0c6ae0e35d3e020db55b5b826955da66b14b7f6Winson Chungimport java.util.Set; 49e428e292c27e650ab4de76b78728ba55019cd282Winson Chung 5031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectpublic class InstallShortcutReceiver extends BroadcastReceiver { 514e871a217b286775dc6c07feb6d9f1d7a7e914beBjorn Bringert private static final String TAG = "InstallShortcutReceiver"; 524e871a217b286775dc6c07feb6d9f1d7a7e914beBjorn Bringert private static final boolean DBG = false; 534e871a217b286775dc6c07feb6d9f1d7a7e914beBjorn Bringert 542350bc97851eea1662eee43d61290eb7a8382021Sunny Goyal private static final String ACTION_INSTALL_SHORTCUT = 5594d6768c65929efa21bb893fdef7f269d65da3c3Winson Chung "com.android.launcher.action.INSTALL_SHORTCUT"; 56f0c6ae0e35d3e020db55b5b826955da66b14b7f6Winson Chung 572350bc97851eea1662eee43d61290eb7a8382021Sunny Goyal private static final String LAUNCH_INTENT_KEY = "intent.launch"; 582350bc97851eea1662eee43d61290eb7a8382021Sunny Goyal private static final String NAME_KEY = "name"; 592350bc97851eea1662eee43d61290eb7a8382021Sunny Goyal private static final String ICON_KEY = "icon"; 602350bc97851eea1662eee43d61290eb7a8382021Sunny Goyal private static final String ICON_RESOURCE_NAME_KEY = "iconResource"; 612350bc97851eea1662eee43d61290eb7a8382021Sunny Goyal private static final String ICON_RESOURCE_PACKAGE_NAME_KEY = "iconResourcePackage"; 62e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal 63e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal private static final String APP_SHORTCUT_TYPE_KEY = "isAppShortcut"; 64e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal private static final String USER_HANDLE_KEY = "userHandle"; 65e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal 6648c7a93eb7ef15ef551aee80c179b8e7e0d2399aMichael Jurka // The set of shortcuts that are pending install 672350bc97851eea1662eee43d61290eb7a8382021Sunny Goyal private static final String APPS_PENDING_INSTALL = "apps_to_install"; 6848c7a93eb7ef15ef551aee80c179b8e7e0d2399aMichael Jurka 69f0c6ae0e35d3e020db55b5b826955da66b14b7f6Winson Chung public static final int NEW_SHORTCUT_BOUNCE_DURATION = 450; 70997a92348a6d6e061737399321393449c16cd4d8Winson Chung public static final int NEW_SHORTCUT_STAGGER_DELAY = 85; 71f0c6ae0e35d3e020db55b5b826955da66b14b7f6Winson Chung 72e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal private static final Object sLock = new Object(); 7348c7a93eb7ef15ef551aee80c179b8e7e0d2399aMichael Jurka 7448c7a93eb7ef15ef551aee80c179b8e7e0d2399aMichael Jurka private static void addToInstallQueue( 7548c7a93eb7ef15ef551aee80c179b8e7e0d2399aMichael Jurka SharedPreferences sharedPrefs, PendingInstallShortcutInfo info) { 7648c7a93eb7ef15ef551aee80c179b8e7e0d2399aMichael Jurka synchronized(sLock) { 77e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal String encoded = info.encodeToString(); 78e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal if (encoded != null) { 79e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal Set<String> strings = sharedPrefs.getStringSet(APPS_PENDING_INSTALL, null); 80e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal if (strings == null) { 81e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal strings = new HashSet<String>(1); 82e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal } else { 83e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal strings = new HashSet<String>(strings); 8448c7a93eb7ef15ef551aee80c179b8e7e0d2399aMichael Jurka } 85e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal strings.add(encoded); 86d80439875557e8c94052e5b0f0327b656370b5fdSunny Goyal sharedPrefs.edit().putStringSet(APPS_PENDING_INSTALL, strings).apply(); 8748c7a93eb7ef15ef551aee80c179b8e7e0d2399aMichael Jurka } 8848c7a93eb7ef15ef551aee80c179b8e7e0d2399aMichael Jurka } 8948c7a93eb7ef15ef551aee80c179b8e7e0d2399aMichael Jurka } 9048c7a93eb7ef15ef551aee80c179b8e7e0d2399aMichael Jurka 913bbbabc54ac73a4451b0a862a3faac6426b1b7b4Sunny Goyal public static void removeFromInstallQueue(Context context, HashSet<String> packageNames, 92e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal UserHandleCompat user) { 93df95eb12a4d288ffa143a0c3db60e7e98f3e03b9Winson Chung if (packageNames.isEmpty()) { 94df95eb12a4d288ffa143a0c3db60e7e98f3e03b9Winson Chung return; 95df95eb12a4d288ffa143a0c3db60e7e98f3e03b9Winson Chung } 96f725824fa2091cab44cf1bcbfe5b5b8d06475560Sunny Goyal SharedPreferences sp = Utilities.getPrefs(context); 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 } 114d80439875557e8c94052e5b0f0327b656370b5fdSunny Goyal sp.edit().putStringSet(APPS_PENDING_INSTALL, newStrings).apply(); 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 } 135d80439875557e8c94052e5b0f0327b656370b5fdSunny Goyal sharedPrefs.edit().putStringSet(APPS_PENDING_INSTALL, new HashSet<String>()).apply(); 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 } 1487606a412c5a7da2d8eff9bd9425c759f7028d888Sunny Goyal PendingInstallShortcutInfo info = createPendingInfo(context, data); 1497606a412c5a7da2d8eff9bd9425c759f7028d888Sunny Goyal if (info != null) { 150fb5096d07bb3bb59fd4b5db6b68613030169b4bdSunny Goyal if (!info.isLauncherActivity()) { 151fb5096d07bb3bb59fd4b5db6b68613030169b4bdSunny Goyal // Since its a custom shortcut, verify that it is safe to launch. 152fb5096d07bb3bb59fd4b5db6b68613030169b4bdSunny Goyal if (!PackageManagerHelper.hasPermissionForActivity( 153fb5096d07bb3bb59fd4b5db6b68613030169b4bdSunny Goyal context, info.launchIntent, null)) { 154fb5096d07bb3bb59fd4b5db6b68613030169b4bdSunny Goyal // Target cannot be launched, or requires some special permission to launch 155fb5096d07bb3bb59fd4b5db6b68613030169b4bdSunny Goyal Log.e(TAG, "Ignoring malicious intent " + info.launchIntent.toUri(0)); 156fb5096d07bb3bb59fd4b5db6b68613030169b4bdSunny Goyal return; 157fb5096d07bb3bb59fd4b5db6b68613030169b4bdSunny Goyal } 158fb5096d07bb3bb59fd4b5db6b68613030169b4bdSunny Goyal } 1597606a412c5a7da2d8eff9bd9425c759f7028d888Sunny Goyal queuePendingShortcutInfo(info, context); 1603290ec4cc220f97460b3b19f28adaf829ea971e1Sunny Goyal } 1617606a412c5a7da2d8eff9bd9425c759f7028d888Sunny Goyal } 1624e871a217b286775dc6c07feb6d9f1d7a7e914beBjorn Bringert 1637606a412c5a7da2d8eff9bd9425c759f7028d888Sunny Goyal /** 1647606a412c5a7da2d8eff9bd9425c759f7028d888Sunny Goyal * @return true is the extra is either null or is of type {@param type} 1657606a412c5a7da2d8eff9bd9425c759f7028d888Sunny Goyal */ 1667606a412c5a7da2d8eff9bd9425c759f7028d888Sunny Goyal private static boolean isValidExtraType(Intent intent, String key, Class type) { 1677606a412c5a7da2d8eff9bd9425c759f7028d888Sunny Goyal Object extra = intent.getParcelableExtra(key); 1687606a412c5a7da2d8eff9bd9425c759f7028d888Sunny Goyal return extra == null || type.isInstance(extra); 169e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal } 170dff0bfeb901e767ca9b57f9b8051c7fd077626e9Nilesh Agrawal 1717606a412c5a7da2d8eff9bd9425c759f7028d888Sunny Goyal /** 1727606a412c5a7da2d8eff9bd9425c759f7028d888Sunny Goyal * Verifies the intent and creates a {@link PendingInstallShortcutInfo} 1737606a412c5a7da2d8eff9bd9425c759f7028d888Sunny Goyal */ 1747606a412c5a7da2d8eff9bd9425c759f7028d888Sunny Goyal private static PendingInstallShortcutInfo createPendingInfo(Context context, Intent data) { 1757606a412c5a7da2d8eff9bd9425c759f7028d888Sunny Goyal if (!isValidExtraType(data, Intent.EXTRA_SHORTCUT_INTENT, Intent.class) || 1767606a412c5a7da2d8eff9bd9425c759f7028d888Sunny Goyal !(isValidExtraType(data, Intent.EXTRA_SHORTCUT_ICON_RESOURCE, 1777606a412c5a7da2d8eff9bd9425c759f7028d888Sunny Goyal Intent.ShortcutIconResource.class)) || 1787606a412c5a7da2d8eff9bd9425c759f7028d888Sunny Goyal !(isValidExtraType(data, Intent.EXTRA_SHORTCUT_ICON, Bitmap.class))) { 1797606a412c5a7da2d8eff9bd9425c759f7028d888Sunny Goyal 1807606a412c5a7da2d8eff9bd9425c759f7028d888Sunny Goyal if (DBG) Log.e(TAG, "Invalid install shortcut intent"); 1817606a412c5a7da2d8eff9bd9425c759f7028d888Sunny Goyal return null; 1827606a412c5a7da2d8eff9bd9425c759f7028d888Sunny Goyal } 1837606a412c5a7da2d8eff9bd9425c759f7028d888Sunny Goyal 1845c97f51fd9443e461a360ff7852aa223c05d667fSunny Goyal PendingInstallShortcutInfo info = new PendingInstallShortcutInfo(data, context); 1855c97f51fd9443e461a360ff7852aa223c05d667fSunny Goyal if (info.launchIntent == null || info.label == null) { 1865c97f51fd9443e461a360ff7852aa223c05d667fSunny Goyal if (DBG) Log.e(TAG, "Invalid install shortcut intent"); 1875c97f51fd9443e461a360ff7852aa223c05d667fSunny Goyal return null; 1885c97f51fd9443e461a360ff7852aa223c05d667fSunny Goyal } 1897606a412c5a7da2d8eff9bd9425c759f7028d888Sunny Goyal 1907606a412c5a7da2d8eff9bd9425c759f7028d888Sunny Goyal return convertToLauncherActivityIfPossible(info); 1915c97f51fd9443e461a360ff7852aa223c05d667fSunny Goyal } 1925c97f51fd9443e461a360ff7852aa223c05d667fSunny Goyal 1937606a412c5a7da2d8eff9bd9425c759f7028d888Sunny Goyal public static ShortcutInfo fromShortcutIntent(Context context, Intent data) { 1947606a412c5a7da2d8eff9bd9425c759f7028d888Sunny Goyal PendingInstallShortcutInfo info = createPendingInfo(context, data); 1957606a412c5a7da2d8eff9bd9425c759f7028d888Sunny Goyal return info == null ? null : info.getShortcutInfo(); 196e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal } 19748c7a93eb7ef15ef551aee80c179b8e7e0d2399aMichael Jurka 198e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal private static void queuePendingShortcutInfo(PendingInstallShortcutInfo info, Context context) { 199de0fb8fbf11caac382589ab464b50d528942273aWinson Chung // Queue the item up for adding if launcher has not loaded properly yet 200892c74d460ad98c6306420e1127c9aa3e505ba25Winson Chung LauncherAppState app = LauncherAppState.getInstance(); 201e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal boolean launcherNotLoaded = app.getModel().getCallback() == null; 202997a92348a6d6e061737399321393449c16cd4d8Winson Chung 203f725824fa2091cab44cf1bcbfe5b5b8d06475560Sunny Goyal addToInstallQueue(Utilities.getPrefs(context), info); 204997a92348a6d6e061737399321393449c16cd4d8Winson Chung if (!mUseInstallQueue && !launcherNotLoaded) { 205997a92348a6d6e061737399321393449c16cd4d8Winson Chung flushInstallQueue(context); 206f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung } 207f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung } 208f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung 209f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung static void enableInstallQueue() { 210f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung mUseInstallQueue = true; 211f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung } 212f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung static void disableAndFlushInstallQueue(Context context) { 213f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung mUseInstallQueue = false; 214de0fb8fbf11caac382589ab464b50d528942273aWinson Chung flushInstallQueue(context); 215de0fb8fbf11caac382589ab464b50d528942273aWinson Chung } 216de0fb8fbf11caac382589ab464b50d528942273aWinson Chung static void flushInstallQueue(Context context) { 217f725824fa2091cab44cf1bcbfe5b5b8d06475560Sunny Goyal SharedPreferences sp = Utilities.getPrefs(context); 218e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal ArrayList<PendingInstallShortcutInfo> installQueue = getAndClearInstallQueue(sp, context); 219997a92348a6d6e061737399321393449c16cd4d8Winson Chung if (!installQueue.isEmpty()) { 220997a92348a6d6e061737399321393449c16cd4d8Winson Chung Iterator<PendingInstallShortcutInfo> iter = installQueue.iterator(); 221997a92348a6d6e061737399321393449c16cd4d8Winson Chung ArrayList<ItemInfo> addShortcuts = new ArrayList<ItemInfo>(); 222997a92348a6d6e061737399321393449c16cd4d8Winson Chung while (iter.hasNext()) { 223997a92348a6d6e061737399321393449c16cd4d8Winson Chung final PendingInstallShortcutInfo pendingInfo = iter.next(); 224dff0bfeb901e767ca9b57f9b8051c7fd077626e9Nilesh Agrawal 225a28b78e8385f0f590b144038157afc7d34cd48b7Adam Cohen // If the intent specifies a package, make sure the package exists 226e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal String packageName = pendingInfo.getTargetPackage(); 227f2048779990bfd3c20b52149f5e8ab208bf2502aSunny Goyal if (!TextUtils.isEmpty(packageName)) { 228a28b78e8385f0f590b144038157afc7d34cd48b7Adam Cohen UserHandleCompat myUserHandle = UserHandleCompat.myUserHandle(); 229a28b78e8385f0f590b144038157afc7d34cd48b7Adam Cohen if (!LauncherModel.isValidPackage(context, packageName, myUserHandle)) { 230b740f59c7d572d54402e3a74fb2a23c0f1b1af48Sunny Goyal if (DBG) Log.d(TAG, "Ignoring shortcut for absent package: " 231b740f59c7d572d54402e3a74fb2a23c0f1b1af48Sunny Goyal + pendingInfo.launchIntent); 232a28b78e8385f0f590b144038157afc7d34cd48b7Adam Cohen continue; 233a28b78e8385f0f590b144038157afc7d34cd48b7Adam Cohen } 234a28b78e8385f0f590b144038157afc7d34cd48b7Adam Cohen } 235a28b78e8385f0f590b144038157afc7d34cd48b7Adam Cohen 236756adbc3e41ee1edb53c580b8c679f343924fab5Sunny Goyal // Generate a shortcut info to add into the model 237756adbc3e41ee1edb53c580b8c679f343924fab5Sunny Goyal addShortcuts.add(pendingInfo.getShortcutInfo()); 238f0c6ae0e35d3e020db55b5b826955da66b14b7f6Winson Chung } 239f0c6ae0e35d3e020db55b5b826955da66b14b7f6Winson Chung 240997a92348a6d6e061737399321393449c16cd4d8Winson Chung // Add the new apps to the model and bind them 241997a92348a6d6e061737399321393449c16cd4d8Winson Chung if (!addShortcuts.isEmpty()) { 242997a92348a6d6e061737399321393449c16cd4d8Winson Chung LauncherAppState app = LauncherAppState.getInstance(); 24318bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal app.getModel().addAndBindAddedWorkspaceItems(context, addShortcuts); 24431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 24531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 24631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 24731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 248dff0bfeb901e767ca9b57f9b8051c7fd077626e9Nilesh Agrawal /** 2492c1afde5cd60eb13f05aeae0c170e697493ef307Winson Chung * Ensures that we have a valid, non-null name. If the provided name is null, we will return 2502c1afde5cd60eb13f05aeae0c170e697493ef307Winson Chung * the application name instead. 2512c1afde5cd60eb13f05aeae0c170e697493ef307Winson Chung */ 252091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen @Thunk static CharSequence ensureValidName(Context context, Intent intent, CharSequence name) { 2532c1afde5cd60eb13f05aeae0c170e697493ef307Winson Chung if (name == null) { 2542c1afde5cd60eb13f05aeae0c170e697493ef307Winson Chung try { 2552c1afde5cd60eb13f05aeae0c170e697493ef307Winson Chung PackageManager pm = context.getPackageManager(); 2562c1afde5cd60eb13f05aeae0c170e697493ef307Winson Chung ActivityInfo info = pm.getActivityInfo(intent.getComponent(), 0); 25782b016cb56540fe26213e817dd0dd668099c8e20Winson Chung name = info.loadLabel(pm); 2582c1afde5cd60eb13f05aeae0c170e697493ef307Winson Chung } catch (PackageManager.NameNotFoundException nnfe) { 2592c1afde5cd60eb13f05aeae0c170e697493ef307Winson Chung return ""; 2602c1afde5cd60eb13f05aeae0c170e697493ef307Winson Chung } 2612c1afde5cd60eb13f05aeae0c170e697493ef307Winson Chung } 2622c1afde5cd60eb13f05aeae0c170e697493ef307Winson Chung return name; 26331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 264e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal 265e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal private static class PendingInstallShortcutInfo { 266e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal 267e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal final LauncherActivityInfoCompat activityInfo; 268e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal 269e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal final Intent data; 270e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal final Context mContext; 271e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal final Intent launchIntent; 272e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal final String label; 273e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal final UserHandleCompat user; 274e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal 275e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal /** 276e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal * Initializes a PendingInstallShortcutInfo received from a different app. 277e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal */ 278e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal public PendingInstallShortcutInfo(Intent data, Context context) { 279e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal this.data = data; 280e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal mContext = context; 281e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal 282e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal launchIntent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT); 283e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal label = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME); 284e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal user = UserHandleCompat.myUserHandle(); 285e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal activityInfo = null; 286e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal } 287e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal 288e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal /** 289e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal * Initializes a PendingInstallShortcutInfo to represent a launcher target. 290e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal */ 291e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal public PendingInstallShortcutInfo(LauncherActivityInfoCompat info, Context context) { 292e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal this.data = null; 293e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal mContext = context; 294e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal activityInfo = info; 295e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal user = info.getUser(); 296e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal 297e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal launchIntent = AppInfo.makeLaunchIntent(context, info, user); 298e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal label = info.getLabel().toString(); 299e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal } 300e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal 301e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal public String encodeToString() { 302e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal if (activityInfo != null) { 303e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal try { 304e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal // If it a launcher target, we only need component name, and user to 305e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal // recreate this. 306e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal return new JSONStringer() 307e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal .object() 308e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal .key(LAUNCH_INTENT_KEY).value(launchIntent.toUri(0)) 309e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal .key(APP_SHORTCUT_TYPE_KEY).value(true) 310e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal .key(USER_HANDLE_KEY).value(UserManagerCompat.getInstance(mContext) 311e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal .getSerialNumberForUser(user)) 312e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal .endObject().toString(); 313e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal } catch (JSONException e) { 314e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal Log.d(TAG, "Exception when adding shortcut: " + e); 315e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal return null; 316e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal } 317e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal } 318e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal 319e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal if (launchIntent.getAction() == null) { 320e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal launchIntent.setAction(Intent.ACTION_VIEW); 321e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal } else if (launchIntent.getAction().equals(Intent.ACTION_MAIN) && 322e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal launchIntent.getCategories() != null && 323e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal launchIntent.getCategories().contains(Intent.CATEGORY_LAUNCHER)) { 324e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal launchIntent.addFlags( 325e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); 326e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal } 327e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal 328e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal // This name is only used for comparisons and notifications, so fall back to activity 329e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal // name if not supplied 330e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal String name = ensureValidName(mContext, launchIntent, label).toString(); 331e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal Bitmap icon = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON); 332e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal Intent.ShortcutIconResource iconResource = 333e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE); 334e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal 335e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal // Only encode the parameters which are supported by the API. 336e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal try { 337e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal JSONStringer json = new JSONStringer() 338e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal .object() 339e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal .key(LAUNCH_INTENT_KEY).value(launchIntent.toUri(0)) 340e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal .key(NAME_KEY).value(name); 341e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal if (icon != null) { 3425b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal byte[] iconByteArray = Utilities.flattenBitmap(icon); 343e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal json = json.key(ICON_KEY).value( 344e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal Base64.encodeToString( 345e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal iconByteArray, 0, iconByteArray.length, Base64.DEFAULT)); 346e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal } 347e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal if (iconResource != null) { 348e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal json = json.key(ICON_RESOURCE_NAME_KEY).value(iconResource.resourceName); 349e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal json = json.key(ICON_RESOURCE_PACKAGE_NAME_KEY) 350e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal .value(iconResource.packageName); 351e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal } 352e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal return json.endObject().toString(); 353e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal } catch (JSONException e) { 354e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal Log.d(TAG, "Exception when adding shortcut: " + e); 355e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal } 356e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal return null; 357e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal } 358e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal 359e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal public ShortcutInfo getShortcutInfo() { 360e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal if (activityInfo != null) { 36110923b30a22b4ec8d10cf8536bddf3f176e6c26fSunny Goyal return new ShortcutInfo(activityInfo, mContext); 362e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal } else { 363e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal return LauncherAppState.getInstance().getModel().infoFromShortcutIntent(mContext, data); 364e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal } 365e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal } 366e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal 367e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal public String getTargetPackage() { 368e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal String packageName = launchIntent.getPackage(); 369e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal if (packageName == null) { 370e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal packageName = launchIntent.getComponent() == null ? null : 371e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal launchIntent.getComponent().getPackageName(); 372e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal } 373e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal return packageName; 374e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal } 3750b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal 376b740f59c7d572d54402e3a74fb2a23c0f1b1af48Sunny Goyal public boolean isLauncherActivity() { 3770b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal return activityInfo != null; 3780b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal } 379e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal } 380e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal 381e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal private static PendingInstallShortcutInfo decode(String encoded, Context context) { 382e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal try { 383e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal JSONObject object = (JSONObject) new JSONTokener(encoded).nextValue(); 384e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal Intent launcherIntent = Intent.parseUri(object.getString(LAUNCH_INTENT_KEY), 0); 385e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal 386e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal if (object.optBoolean(APP_SHORTCUT_TYPE_KEY)) { 387e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal // The is an internal launcher target shortcut. 388e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal UserHandleCompat user = UserManagerCompat.getInstance(context) 389e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal .getUserForSerialNumber(object.getLong(USER_HANDLE_KEY)); 39006910a88445c46fb95c9ad5ff83793e37b6af692Sunny Goyal if (user == null) { 39106910a88445c46fb95c9ad5ff83793e37b6af692Sunny Goyal return null; 39206910a88445c46fb95c9ad5ff83793e37b6af692Sunny Goyal } 393e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal 394e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal LauncherActivityInfoCompat info = LauncherAppsCompat.getInstance(context) 395e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal .resolveActivity(launcherIntent, user); 396e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal return info == null ? null : new PendingInstallShortcutInfo(info, context); 397e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal } 398e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal 399e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal Intent data = new Intent(); 400e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal data.putExtra(Intent.EXTRA_SHORTCUT_INTENT, launcherIntent); 401e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal data.putExtra(Intent.EXTRA_SHORTCUT_NAME, object.getString(NAME_KEY)); 402e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal 403e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal String iconBase64 = object.optString(ICON_KEY); 404e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal String iconResourceName = object.optString(ICON_RESOURCE_NAME_KEY); 405e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal String iconResourcePackageName = object.optString(ICON_RESOURCE_PACKAGE_NAME_KEY); 406e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal if (iconBase64 != null && !iconBase64.isEmpty()) { 407e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal byte[] iconArray = Base64.decode(iconBase64, Base64.DEFAULT); 408e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal Bitmap b = BitmapFactory.decodeByteArray(iconArray, 0, iconArray.length); 409e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal data.putExtra(Intent.EXTRA_SHORTCUT_ICON, b); 410e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal } else if (iconResourceName != null && !iconResourceName.isEmpty()) { 411e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal Intent.ShortcutIconResource iconResource = 412e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal new Intent.ShortcutIconResource(); 413e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal iconResource.resourceName = iconResourceName; 414e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal iconResource.packageName = iconResourcePackageName; 415e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal data.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, iconResource); 416e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal } 417e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal 418e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal return new PendingInstallShortcutInfo(data, context); 419b740f59c7d572d54402e3a74fb2a23c0f1b1af48Sunny Goyal } catch (JSONException | URISyntaxException e) { 420e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal Log.d(TAG, "Exception reading shortcut to add: " + e); 421e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal } 422e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal return null; 423e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal } 4240b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal 4250b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal /** 4260b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal * Tries to create a new PendingInstallShortcutInfo which represents the same target, 4270b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal * but is an app target and not a shortcut. 4280b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal * @return the newly created info or the original one. 4290b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal */ 4300b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal private static PendingInstallShortcutInfo convertToLauncherActivityIfPossible( 4310b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal PendingInstallShortcutInfo original) { 432b740f59c7d572d54402e3a74fb2a23c0f1b1af48Sunny Goyal if (original.isLauncherActivity()) { 4330b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal // Already an activity target 4340b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal return original; 4350b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal } 4365c97f51fd9443e461a360ff7852aa223c05d667fSunny Goyal if (!Utilities.isLauncherAppTarget(original.launchIntent) 4370b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal || !original.user.equals(UserHandleCompat.myUserHandle())) { 4380b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal // We can only convert shortcuts which point to a main activity in the current user. 4390b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal return original; 4400b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal } 4410b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal 4420b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal PackageManager pm = original.mContext.getPackageManager(); 4430b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal ResolveInfo info = pm.resolveActivity(original.launchIntent, 0); 4440b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal 4450b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal if (info == null) { 4460b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal return original; 4470b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal } 4480b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal 4490b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal // Ignore any conflicts in the label name, as that can change based on locale. 4500b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal LauncherActivityInfoCompat launcherInfo = LauncherActivityInfoCompat 4510b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal .fromResolveInfo(info, original.mContext); 4520b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal return new PendingInstallShortcutInfo(launcherInfo, original.mContext); 4530b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal } 45431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project} 455