Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b4a192b5 authored by Sunny Goyal's avatar Sunny Goyal Committed by Android (Google) Code Review
Browse files

Merge "Adding support for deep shortcuts in Install queue" into ub-launcher3-master

parents 55cb70bf f75baa9f
Loading
Loading
Loading
Loading
+137 −64
Original line number Diff line number Diff line
@@ -32,6 +32,9 @@ import com.android.launcher3.compat.LauncherActivityInfoCompat;
import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.compat.UserHandleCompat;
import com.android.launcher3.compat.UserManagerCompat;
import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.shortcuts.ShortcutInfoCompat;
import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.Preconditions;
import com.android.launcher3.util.Provider;
@@ -40,10 +43,10 @@ import com.android.launcher3.util.Thunk;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONStringer;
import org.json.JSONTokener;

import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
@@ -63,6 +66,7 @@ public class InstallShortcutReceiver extends BroadcastReceiver {
    private static final String ICON_RESOURCE_PACKAGE_NAME_KEY = "iconResourcePackage";

    private static final String APP_SHORTCUT_TYPE_KEY = "isAppShortcut";
    private static final String DEEPSHORTCUT_TYPE_KEY = "isDeepShortcut";
    private static final String USER_HANDLE_KEY = "userHandle";

    // The set of shortcuts that are pending install
@@ -98,19 +102,25 @@ public class InstallShortcutReceiver extends BroadcastReceiver {
                Log.d(TAG, "APPS_PENDING_INSTALL: " + strings
                        + ", removing packages: " + packageNames);
            }
            if (strings != null) {
                Set<String> newStrings = new HashSet<String>(strings);
            if (Utilities.isEmpty(strings)) {
                return;
            }
            Set<String> newStrings = new HashSet<>(strings);
            Iterator<String> newStringsIter = newStrings.iterator();
            while (newStringsIter.hasNext()) {
                String encoded = newStringsIter.next();
                    PendingInstallShortcutInfo info = decode(encoded, context);
                    if (info == null || (packageNames.contains(info.getTargetPackage())
                            && user.equals(info.user))) {
                try {
                    Decoder decoder = new Decoder(encoded, context);
                    if (packageNames.contains(getIntentPackage(decoder.launcherIntent)) &&
                            user.equals(decoder.user)) {
                        newStringsIter.remove();
                    }
                } catch (JSONException | URISyntaxException e) {
                    Log.d(TAG, "Exception reading shortcut to add: " + e);
                    newStringsIter.remove();
                }
                sp.edit().putStringSet(APPS_PENDING_INSTALL, newStrings).apply();
            }
            sp.edit().putStringSet(APPS_PENDING_INSTALL, newStrings).apply();
        }
    }

@@ -178,7 +188,8 @@ public class InstallShortcutReceiver extends BroadcastReceiver {
            return null;
        }

        PendingInstallShortcutInfo info = new PendingInstallShortcutInfo(data, context);
        PendingInstallShortcutInfo info = new PendingInstallShortcutInfo(
                data, UserHandleCompat.myUserHandle(), context);
        if (info.launchIntent == null || info.label == null) {
            if (DBG) Log.e(TAG, "Invalid install shortcut intent");
            return null;
@@ -192,6 +203,31 @@ public class InstallShortcutReceiver extends BroadcastReceiver {
        return info == null ? null : info.getShortcutInfo();
    }

    public static void queueShortcut(ShortcutInfoCompat info, Context context) {
        queuePendingShortcutInfo(new PendingInstallShortcutInfo(info, context), context);
    }

    public static HashSet<ShortcutKey> getPendingShortcuts(Context context) {
        HashSet<ShortcutKey> result = new HashSet<>();

        Set<String> strings = Utilities.getPrefs(context).getStringSet(APPS_PENDING_INSTALL, null);
        if (Utilities.isEmpty(strings)) {
            return result;
        }

        for (String encoded : strings) {
            try {
                Decoder decoder = new Decoder(encoded, context);
                if (decoder.optBoolean(DEEPSHORTCUT_TYPE_KEY)) {
                    result.add(ShortcutKey.fromIntent(decoder.launcherIntent, decoder.user));
                }
            } catch (JSONException | URISyntaxException e) {
                Log.d(TAG, "Exception reading shortcut to add: " + e);
            }
        }
        return result;
    }

    private static void queuePendingShortcutInfo(PendingInstallShortcutInfo info, Context context) {
        // Queue the item up for adding if launcher has not loaded properly yet
        LauncherAppState app = LauncherAppState.getInstance();
@@ -239,6 +275,7 @@ public class InstallShortcutReceiver extends BroadcastReceiver {
    private static class PendingInstallShortcutInfo {

        final LauncherActivityInfoCompat activityInfo;
        final ShortcutInfoCompat shortcutInfo;

        final Intent data;
        final Context mContext;
@@ -249,14 +286,15 @@ public class InstallShortcutReceiver extends BroadcastReceiver {
        /**
         * Initializes a PendingInstallShortcutInfo received from a different app.
         */
        public PendingInstallShortcutInfo(Intent data, Context context) {
        public PendingInstallShortcutInfo(Intent data, UserHandleCompat user, Context context) {
            this.data = data;
            this.user = user;
            mContext = context;

            launchIntent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);
            label = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
            user = UserHandleCompat.myUserHandle();
            activityInfo = null;
            shortcutInfo = null;
        }

        /**
@@ -266,15 +304,30 @@ public class InstallShortcutReceiver extends BroadcastReceiver {
            this.data = null;
            mContext = context;
            activityInfo = info;
            shortcutInfo = null;
            user = info.getUser();

            launchIntent = AppInfo.makeLaunchIntent(context, info, user);
            label = info.getLabel().toString();
        }

        /**
         * Initializes a PendingInstallShortcutInfo to represent a launcher target.
         */
        public PendingInstallShortcutInfo(ShortcutInfoCompat info, Context context) {
            this.data = null;
            shortcutInfo = info;
            mContext = context;
            activityInfo = null;
            user = info.getUserHandle();

            launchIntent = info.makeIntent(context);
            label = info.getShortLabel().toString();
        }

        public String encodeToString() {
            if (activityInfo != null) {
            try {
                if (activityInfo != null) {
                    // If it a launcher target, we only need component name, and user to
                    // recreate this.
                    return new JSONStringer()
@@ -284,10 +337,16 @@ public class InstallShortcutReceiver extends BroadcastReceiver {
                        .key(USER_HANDLE_KEY).value(UserManagerCompat.getInstance(mContext)
                                .getSerialNumberForUser(user))
                        .endObject().toString();
                } catch (JSONException e) {
                    Log.d(TAG, "Exception when adding shortcut: " + e);
                    return null;
                }
                } else if (shortcutInfo != null) {
                    // If it a launcher target, we only need component name, and user to
                    // recreate this.
                    return new JSONStringer()
                            .object()
                            .key(LAUNCH_INTENT_KEY).value(launchIntent.toUri(0))
                            .key(DEEPSHORTCUT_TYPE_KEY).value(true)
                            .key(USER_HANDLE_KEY).value(UserManagerCompat.getInstance(mContext)
                                    .getSerialNumberForUser(user))
                            .endObject().toString();
                }

                if (launchIntent.getAction() == null) {
@@ -307,7 +366,6 @@ public class InstallShortcutReceiver extends BroadcastReceiver {
                    data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE);

                // Only encode the parameters which are supported by the API.
            try {
                JSONStringer json = new JSONStringer()
                    .object()
                    .key(LAUNCH_INTENT_KEY).value(launchIntent.toUri(0))
@@ -326,57 +384,56 @@ public class InstallShortcutReceiver extends BroadcastReceiver {
                return json.endObject().toString();
            } catch (JSONException e) {
                Log.d(TAG, "Exception when adding shortcut: " + e);
            }
                return null;
            }
        }

        public ShortcutInfo getShortcutInfo() {
            if (activityInfo != null) {
                return new ShortcutInfo(activityInfo, mContext);
            } else if (shortcutInfo != null) {
                return new ShortcutInfo(shortcutInfo, mContext);
            } else {
                return LauncherAppState.getInstance().getModel().infoFromShortcutIntent(mContext, data);
            }
        }

        public String getTargetPackage() {
            String packageName = launchIntent.getPackage();
            if (packageName == null) {
                packageName = launchIntent.getComponent() == null ? null :
                    launchIntent.getComponent().getPackageName();
            }
            return packageName;
        }

        public boolean isLauncherActivity() {
            return activityInfo != null;
        }
    }

    private static PendingInstallShortcutInfo decode(String encoded, Context context) {
        try {
            JSONObject object = (JSONObject) new JSONTokener(encoded).nextValue();
            Intent launcherIntent = Intent.parseUri(object.getString(LAUNCH_INTENT_KEY), 0);

            if (object.optBoolean(APP_SHORTCUT_TYPE_KEY)) {
                // The is an internal launcher target shortcut.
                UserHandleCompat user = UserManagerCompat.getInstance(context)
                        .getUserForSerialNumber(object.getLong(USER_HANDLE_KEY));
                if (user == null) {
                    return null;
    private static String getIntentPackage(Intent intent) {
        return intent.getComponent() == null
                ? intent.getPackage() : intent.getComponent().getPackageName();
    }

    private static PendingInstallShortcutInfo decode(String encoded, Context context) {
        try {
            Decoder decoder = new Decoder(encoded, context);
            if (decoder.optBoolean(APP_SHORTCUT_TYPE_KEY)) {
                LauncherActivityInfoCompat info = LauncherAppsCompat.getInstance(context)
                        .resolveActivity(launcherIntent, user);
                        .resolveActivity(decoder.launcherIntent, decoder.user);
                return info == null ? null : new PendingInstallShortcutInfo(info, context);
            } else if (decoder.optBoolean(DEEPSHORTCUT_TYPE_KEY)) {
                DeepShortcutManager sm = DeepShortcutManager.getInstance(context);
                List<ShortcutInfoCompat> si = sm.queryForFullDetails(
                        decoder.launcherIntent.getPackage(),
                        Arrays.asList(ShortcutInfoCompat.EXTRA_SHORTCUT_ID), decoder.user);
                if (si.isEmpty()) {
                    return null;
                } else {
                    return new PendingInstallShortcutInfo(si.get(0), context);
                }
            }

            Intent data = new Intent();
            data.putExtra(Intent.EXTRA_SHORTCUT_INTENT, launcherIntent);
            data.putExtra(Intent.EXTRA_SHORTCUT_NAME, object.getString(NAME_KEY));
            data.putExtra(Intent.EXTRA_SHORTCUT_INTENT, decoder.launcherIntent);
            data.putExtra(Intent.EXTRA_SHORTCUT_NAME, decoder.getString(NAME_KEY));

            String iconBase64 = object.optString(ICON_KEY);
            String iconResourceName = object.optString(ICON_RESOURCE_NAME_KEY);
            String iconResourcePackageName = object.optString(ICON_RESOURCE_PACKAGE_NAME_KEY);
            String iconBase64 = decoder.optString(ICON_KEY);
            String iconResourceName = decoder.optString(ICON_RESOURCE_NAME_KEY);
            String iconResourcePackageName = decoder.optString(ICON_RESOURCE_PACKAGE_NAME_KEY);
            if (iconBase64 != null && !iconBase64.isEmpty()) {
                byte[] iconArray = Base64.decode(iconBase64, Base64.DEFAULT);
                Bitmap b = BitmapFactory.decodeByteArray(iconArray, 0, iconArray.length);
@@ -389,13 +446,29 @@ public class InstallShortcutReceiver extends BroadcastReceiver {
                data.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, iconResource);
            }

            return new PendingInstallShortcutInfo(data, context);
            return new PendingInstallShortcutInfo(data, decoder.user, context);
        } catch (JSONException | URISyntaxException e) {
            Log.d(TAG, "Exception reading shortcut to add: " + e);
        }
        return null;
    }

    private static class Decoder extends JSONObject {
        public final Intent launcherIntent;
        public final UserHandleCompat user;

        private Decoder(String encoded, Context context) throws JSONException, URISyntaxException {
            super(encoded);
            launcherIntent = Intent.parseUri(getString(LAUNCH_INTENT_KEY), 0);
            user = has(USER_HANDLE_KEY) ? UserManagerCompat.getInstance(context)
                    .getUserForSerialNumber(getLong(USER_HANDLE_KEY))
                    : UserHandleCompat.myUserHandle();
            if (user == null) {
                throw new JSONException("Invalid user");
            }
        }
    }

    /**
     * Tries to create a new PendingInstallShortcutInfo which represents the same target,
     * but is an app target and not a shortcut.
@@ -441,7 +514,7 @@ public class InstallShortcutReceiver extends BroadcastReceiver {
            LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(mContext);
            for (PendingInstallShortcutInfo pendingInfo : mPendingItems) {
                // If the intent specifies a package, make sure the package exists
                String packageName = pendingInfo.getTargetPackage();
                String packageName = getIntentPackage(pendingInfo.launchIntent);
                if (!TextUtils.isEmpty(packageName) && !launcherApps.isPackageEnabledForProfile(
                        packageName, pendingInfo.user)) {
                    if (DBG) Log.d(TAG, "Ignoring shortcut for absent package: "
+4 −1
Original line number Diff line number Diff line
@@ -1776,9 +1776,12 @@ public class LauncherModel extends BroadcastReceiver
                }

                // Unpin shortcuts that don't exist on the workspace.
                HashSet<ShortcutKey> pendingShortcuts =
                        InstallShortcutReceiver.getPendingShortcuts(context);
                for (ShortcutKey key : shortcutKeyToPinnedShortcuts.keySet()) {
                    MutableInt numTimesPinned = sBgDataModel.pinnedShortcutCounts.get(key);
                    if (numTimesPinned == null || numTimesPinned.value == 0) {
                    if ((numTimesPinned == null || numTimesPinned.value == 0)
                            && !pendingShortcuts.contains(key)) {
                        // Shortcut is pinned but doesn't exist on the workspace; unpin it.
                        shortcutManager.unpinShortcut(key);
                    }
+7 −3
Original line number Diff line number Diff line
@@ -15,10 +15,12 @@
 */
package com.android.launcher3.model;

import android.content.Context;
import android.util.Log;
import android.util.MutableInt;

import com.android.launcher3.FolderInfo;
import com.android.launcher3.InstallShortcutReceiver;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherAppWidgetInfo;
@@ -123,9 +125,11 @@ public class BgDataModel {
                    // Decrement pinned shortcut count
                    ShortcutKey pinnedShortcut = ShortcutKey.fromShortcutInfo((ShortcutInfo) item);
                    MutableInt count = pinnedShortcutCounts.get(pinnedShortcut);
                    if (count == null || --count.value == 0) {
                        DeepShortcutManager.getInstance(LauncherAppState.getInstance().getContext())
                                .unpinShortcut(pinnedShortcut);
                    Context context = LauncherAppState.getInstance().getContext();
                    if ((count == null || --count.value == 0)
                            && !InstallShortcutReceiver.getPendingShortcuts(context)
                                .contains(pinnedShortcut)) {
                        DeepShortcutManager.getInstance(context).unpinShortcut(pinnedShortcut);
                    }
                    // Fall through.
                }