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