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

Commit 440a1ea8 authored by Makoto Onuki's avatar Makoto Onuki
Browse files

Support multiple intents in ShortcutInfo

Also fix b/30230996.

TODO: Support the sourceBounds argument to LauncherApps.
startShortcut().

Bug 30218829
Bug 30230996

Change-Id: Ibb6c59d5b7c0a320c21d09436d016d0eac94644f
parent ceadb1a8
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -165,10 +165,10 @@ public abstract class ActivityManagerInternal {
            int userId);

    /**
     * Start an activity {@code intent} as if {@code packageName} on user {@code userId} did it.
     * Start activity {@code intents} as if {@code packageName} on user {@code userId} did it.
     *
     * @return error codes used by {@link IActivityManager#startActivity} and its siblings.
     */
    public abstract int startActivityAsPackage(String packageName,
            int userId, Intent intent, Bundle bOptions);
    public abstract int startActivitiesAsPackage(String packageName,
            int userId, Intent[] intents, Bundle bOptions);
}
+136 −60
Original line number Diff line number Diff line
@@ -182,16 +182,16 @@ public final class ShortcutInfo implements Parcelable {
    private ArraySet<String> mCategories;

    /**
     * Intent *with extras removed*.
     * Intents *with extras removed*.
     */
    @Nullable
    private Intent mIntent;
    private Intent[] mIntents;

    /**
     * Extras for the intent.
     * Extras for the intents.
     */
    @Nullable
    private PersistableBundle mIntentPersistableExtras;
    private PersistableBundle[] mIntentPersistableExtrases;

    private int mRank;

@@ -241,20 +241,36 @@ public final class ShortcutInfo implements Parcelable {
        mDisabledMessage = b.mDisabledMessage;
        mDisabledMessageResId = b.mDisabledMessageResId;
        mCategories = cloneCategories(b.mCategories);
        mIntent = b.mIntent;
        if (mIntent != null) {
            final Bundle intentExtras = mIntent.getExtras();
            if (intentExtras != null) {
                mIntent.replaceExtras((Bundle) null);
                mIntentPersistableExtras = new PersistableBundle(intentExtras);
            }
        }
        mIntents = cloneIntents(b.mIntents);
        fixUpIntentExtras();
        mRank = b.mRank;
        mExtras = b.mExtras;
        updateTimestamp();
    }

    private ArraySet<String> cloneCategories(Set<String> source) {
    /**
     * Extract extras from {@link #mIntents} and set them to {@link #mIntentPersistableExtrases}
     * as {@link PersistableBundle}, and remove extras from the original intents.
     */
    private void fixUpIntentExtras() {
        if (mIntents == null) {
            mIntentPersistableExtrases = null;
            return;
        }
        mIntentPersistableExtrases = new PersistableBundle[mIntents.length];
        for (int i = 0; i < mIntents.length; i++) {
            final Intent intent = mIntents[i];
            final Bundle extras = intent.getExtras();
            if (extras == null) {
                mIntentPersistableExtrases[i] = null;
            } else {
                mIntentPersistableExtrases[i] = new PersistableBundle(extras);
                intent.replaceExtras((Bundle) null);
            }
        }
    }

    private static ArraySet<String> cloneCategories(Set<String> source) {
        if (source == null) {
            return null;
        }
@@ -267,6 +283,32 @@ public final class ShortcutInfo implements Parcelable {
        return ret;
    }

    private static Intent[] cloneIntents(Intent[] intents) {
        if (intents == null) {
            return null;
        }
        final Intent[] ret = new Intent[intents.length];
        for (int i = 0; i < ret.length; i++) {
            if (intents[i] != null) {
                ret[i] = new Intent(intents[i]);
            }
        }
        return ret;
    }

    private static PersistableBundle[] clonePersistableBundle(PersistableBundle[] bundle) {
        if (bundle == null) {
            return null;
        }
        final PersistableBundle[] ret = new PersistableBundle[bundle.length];
        for (int i = 0; i < ret.length; i++) {
            if (bundle[i] != null) {
                ret[i] = new PersistableBundle(bundle[i]);
            }
        }
        return ret;
    }

    /**
     * Throws if any of the mandatory fields is not set.
     *
@@ -278,7 +320,8 @@ public final class ShortcutInfo implements Parcelable {
        if (mTitle == null && mTitleResId == 0) {
            throw new IllegalArgumentException("Short label must be provided");
        }
        Preconditions.checkNotNull(mIntent, "Shortcut Intent must be provided");
        Preconditions.checkNotNull(mIntents, "Shortcut Intent must be provided");
        Preconditions.checkArgument(mIntents.length > 0, "Shortcut Intent must be provided");
    }

    /**
@@ -310,8 +353,9 @@ public final class ShortcutInfo implements Parcelable {
            mDisabledMessageResId = source.mDisabledMessageResId;
            mCategories = cloneCategories(source.mCategories);
            if ((cloneFlags & CLONE_REMOVE_INTENT) == 0) {
                mIntent = source.mIntent;
                mIntentPersistableExtras = source.mIntentPersistableExtras;
                mIntents = cloneIntents(source.mIntents);
                mIntentPersistableExtrases =
                        clonePersistableBundle(source.mIntentPersistableExtrases);
            }
            mRank = source.mRank;
            mExtras = source.mExtras;
@@ -620,9 +664,10 @@ public final class ShortcutInfo implements Parcelable {
        if (source.mCategories != null) {
            mCategories = cloneCategories(source.mCategories);
        }
        if (source.mIntent != null) {
            mIntent = source.mIntent;
            mIntentPersistableExtras = source.mIntentPersistableExtras;
        if (source.mIntents != null) {
            mIntents = cloneIntents(source.mIntents);
            mIntentPersistableExtrases =
                    clonePersistableBundle(source.mIntentPersistableExtrases);
        }
        if (source.mRank != RANK_NOT_SET) {
            mRank = source.mRank;
@@ -684,7 +729,7 @@ public final class ShortcutInfo implements Parcelable {

        private Set<String> mCategories;

        private Intent mIntent;
        private Intent[] mIntents;

        private int mRank = RANK_NOT_SET;

@@ -912,12 +957,11 @@ public final class ShortcutInfo implements Parcelable {
         * supported so the system can persist them.
         *
         * @see ShortcutInfo#getIntent()
         * @see #setIntents(Intent[])
         */
        @NonNull
        public Builder setIntent(@NonNull Intent intent) {
            mIntent = Preconditions.checkNotNull(intent, "intent cannot be null");
            Preconditions.checkNotNull(mIntent.getAction(), "intent's action must be set");
            return this;
            return setIntents(new Intent[]{intent});
        }

        /**
@@ -930,7 +974,15 @@ public final class ShortcutInfo implements Parcelable {
         */
        @NonNull
        public Builder setIntents(@NonNull Intent[] intents) {
            throw new RuntimeException("NOT SUPPORTED YET");
            Preconditions.checkNotNull(intents, "intents cannot be null");
            Preconditions.checkNotNull(intents.length, "intents cannot be empty");
            for (Intent intent : intents) {
                Preconditions.checkNotNull(intent, "intents cannot contain null");
                Preconditions.checkNotNull(intent.getAction(), "intent's action must be set");
            }
            // Make sure always clone incoming intents.
            mIntents = cloneIntents(intents);
            return this;
        }

        /**
@@ -1098,7 +1150,7 @@ public final class ShortcutInfo implements Parcelable {
    }

    /**
     * Return the intent.  (Or the last intent set with {@link Builder#setIntents(Intent[])}.
     * Return the intent. If setIntents() was used, then return the last intent in the array.
     *
     * <p>Launcher applications <b>cannot</b> see the intent.  If a {@link ShortcutInfo} is
     * obtained via {@link LauncherApps}, then this method will always return null.
@@ -1108,13 +1160,12 @@ public final class ShortcutInfo implements Parcelable {
     */
    @Nullable
    public Intent getIntent() {
        if (mIntent == null) {
        if (mIntents == null || mIntents.length == 0) {
            return null;
        }
        final Intent intent = new Intent(mIntent);
        intent.replaceExtras(
                mIntentPersistableExtras != null ? new Bundle(mIntentPersistableExtras) : null);
        return intent;
        final int last = mIntents.length - 1;
        final Intent intent = new Intent(mIntents[last]);
        return setIntentExtras(intent, mIntentPersistableExtrases[last]);
    }

    /**
@@ -1127,27 +1178,34 @@ public final class ShortcutInfo implements Parcelable {
     * @see Builder#setIntents(Intent[])
     */
    @Nullable
    public Intent getIntents() {
        throw new RuntimeException("NOT SUPPORTED YET");
    public Intent[] getIntents() {
        final Intent[] ret = new Intent[mIntents.length];

        for (int i = 0; i < ret.length; i++) {
            ret[i] = new Intent(mIntents[i]);
            setIntentExtras(ret[i], mIntentPersistableExtrases[i]);
        }

        return ret;
    }

    /**
     * Return "raw" intent, which is the original intent without the extras.
     * Return "raw" intents, which is the original intents without the extras.
     * @hide
     */
    @Nullable
    public Intent getIntentNoExtras() {
        return mIntent;
    public Intent[] getIntentsNoExtras() {
        return mIntents;
    }

    /**
     * The extras in the intent.  We convert extras into {@link PersistableBundle} so we can
     * The extras in the intents.  We convert extras into {@link PersistableBundle} so we can
     * persist them.
     * @hide
     */
    @Nullable
    public PersistableBundle getIntentPersistableExtras() {
        return mIntentPersistableExtras;
    public PersistableBundle[] getIntentPersistableExtrases() {
        return mIntentPersistableExtrases;
    }

    /**
@@ -1500,19 +1558,22 @@ public final class ShortcutInfo implements Parcelable {
     *
     * @hide
     */
    public void setIntent(Intent intent) throws IllegalArgumentException {
        Preconditions.checkNotNull(intent);

        final Bundle intentExtras = intent.getExtras();
    public void setIntents(Intent[] intents) throws IllegalArgumentException {
        Preconditions.checkNotNull(intents);
        Preconditions.checkArgument(intents.length > 0);

        mIntent = intent;
        mIntents = cloneIntents(intents);
        fixUpIntentExtras();
    }

        if (intentExtras != null) {
    /** @hide */
    public static Intent setIntentExtras(Intent intent, PersistableBundle extras) {
        if (extras == null) {
            intent.replaceExtras((Bundle) null);
            mIntentPersistableExtras = new PersistableBundle(intentExtras);
        } else {
            mIntentPersistableExtras = null;
            intent.replaceExtras(new Bundle(extras));
        }
        return intent;
    }

    /**
@@ -1546,8 +1607,8 @@ public final class ShortcutInfo implements Parcelable {
        mTextResId = source.readInt();
        mDisabledMessage = source.readCharSequence();
        mDisabledMessageResId = source.readInt();
        mIntent = source.readParcelable(cl);
        mIntentPersistableExtras = source.readParcelable(cl);
        mIntents = source.readParcelableArray(cl, Intent.class);
        mIntentPersistableExtrases = source.readParcelableArray(cl, PersistableBundle.class);
        mRank = source.readInt();
        mExtras = source.readParcelable(cl);
        mBitmapPath = source.readString();
@@ -1592,8 +1653,8 @@ public final class ShortcutInfo implements Parcelable {
        dest.writeCharSequence(mDisabledMessage);
        dest.writeInt(mDisabledMessageResId);

        dest.writeParcelable(mIntent, flags);
        dest.writeParcelable(mIntentPersistableExtras, flags);
        dest.writeParcelableArray(mIntents, flags);
        dest.writeParcelableArray(mIntentPersistableExtrases, flags);
        dest.writeInt(mRank);
        dest.writeParcelable(mExtras, flags);
        dest.writeString(mBitmapPath);
@@ -1723,11 +1784,27 @@ public final class ShortcutInfo implements Parcelable {
        sb.append(", timestamp=");
        sb.append(mLastChangedTimestamp);

        sb.append(", intent=");
        sb.append(mIntent);

        sb.append(", intentExtras=");
        sb.append(secure ? "***" : mIntentPersistableExtras);
        sb.append(", intents=");
        if (mIntents == null) {
            sb.append("null");
        } else {
            if (secure) {
                sb.append("size:");
                sb.append(mIntents.length);
            } else {
                final int size = mIntents.length;
                sb.append("[");
                String sep = "";
                for (int i = 0; i < size; i++) {
                    sb.append(sep);
                    sep = ", ";
                    sb.append(mIntents[i]);
                    sb.append("/");
                    sb.append(mIntentPersistableExtrases[i]);
                }
                sb.append("]");
            }
        }

        sb.append(", extras=");
        sb.append(mExtras);
@@ -1754,9 +1831,8 @@ public final class ShortcutInfo implements Parcelable {
            Icon icon, CharSequence title, int titleResId, String titleResName,
            CharSequence text, int textResId, String textResName,
            CharSequence disabledMessage, int disabledMessageResId, String disabledMessageResName,
            Set<String> categories,
            Intent intent, PersistableBundle intentPersistableExtras,
            int rank, PersistableBundle extras, long lastChangedTimestamp,
            Set<String> categories, Intent[] intentsWithExtras, int rank, PersistableBundle extras,
            long lastChangedTimestamp,
            int flags, int iconResId, String iconResName, String bitmapPath) {
        mUserId = userId;
        mId = id;
@@ -1773,8 +1849,8 @@ public final class ShortcutInfo implements Parcelable {
        mDisabledMessageResId = disabledMessageResId;
        mDisabledMessageResName = disabledMessageResName;
        mCategories = cloneCategories(categories);
        mIntent = intent;
        mIntentPersistableExtras = intentPersistableExtras;
        mIntents = cloneIntents(intentsWithExtras);
        fixUpIntentExtras();
        mRank = rank;
        mExtras = extras;
        mLastChangedTimestamp = lastChangedTimestamp;
+2 −1
Original line number Diff line number Diff line
@@ -53,7 +53,8 @@ public abstract class ShortcutServiceInternal {
            @NonNull String callingPackage, @NonNull String packageName,
            @NonNull List<String> shortcutIds, int userId);

    public abstract Intent createShortcutIntent(int launcherUserId, @NonNull String callingPackage,
    public abstract Intent[] createShortcutIntents(
            int launcherUserId, @NonNull String callingPackage,
            @NonNull String packageName, @NonNull String shortcutId, int userId);

    public abstract void addListener(@NonNull ShortcutChangeListener listener);
+15 −0
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamClass;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
@@ -2571,6 +2572,20 @@ public final class Parcel {
        return p;
    }

    /** @hide */
    public final <T extends Parcelable> T[] readParcelableArray(ClassLoader loader,
            Class<T> clazz) {
        int N = readInt();
        if (N < 0) {
            return null;
        }
        T[] p = (T[]) Array.newInstance(clazz, N);
        for (int i = 0; i < N; i++) {
            p[i] = readParcelable(loader);
        }
        return p;
    }

    /**
     * Read and return a new Serializable object from the parcel.
     * @return the Serializable object, or null if the Serializable name
+8 −6
Original line number Diff line number Diff line
@@ -21800,10 +21800,13 @@ public final class ActivityManagerService extends ActivityManagerNative
        }
        @Override
        public int startActivityAsPackage(String packageName, int userId, Intent intent,
        public int startActivitiesAsPackage(String packageName, int userId, Intent[] intents,
                Bundle bOptions) {
            Preconditions.checkNotNull(intent, "intent");
            final String resolvedType = intent.resolveTypeIfNeeded(mContext.getContentResolver());
            Preconditions.checkNotNull(intents, "intents");
            final String[] resolvedTypes = new String[intents.length];
            for (int i = 0; i < intents.length; i++) {
                resolvedTypes[i] = intents[i].resolveTypeIfNeeded(mContext.getContentResolver());
            }
            // UID of the package on user userId.
            // "= 0" is needed because otherwise catch(RemoteException) would make it look like
@@ -21817,9 +21820,8 @@ public final class ActivityManagerService extends ActivityManagerNative
            }
            synchronized (ActivityManagerService.this) {
                return startActivityInPackage(packageUid, packageName, intent, resolvedType,
                        /*resultTo*/ null, /*resultWho*/ null, /*requestCode*/ 0, /*startFlags*/ 0,
                        bOptions, userId, /*container*/ null, /*inTask*/ null);
                return startActivitiesInPackage(packageUid, packageName, intents, resolvedTypes,
                        /*resultTo*/ null, bOptions, userId);
            }
        }
    }
Loading