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