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

Commit 14242afe authored by Mehdi Alizadeh's avatar Mehdi Alizadeh
Browse files

Adds API to set persons and isLongLived in ShortcutInfo

Test: atest com.android.server.pm.ShortcutManagerTest1
Test: atest com.android.server.pm.ShortcutManagerTest2
Test: atest com.android.server.pm.ShortcutManagerTest3
Test: atest com.android.server.pm.ShortcutManagerTest4
Test: atest com.android.server.pm.ShortcutManagerTest5
Test: atest com.android.server.pm.ShortcutManagerTest6
Test: atest com.android.server.pm.ShortcutManagerTest7
Test: atest com.android.server.pm.ShortcutManagerTest8
Test: atest com.android.server.pm.ShortcutManagerTest9
Test: atest com.android.server.pm.ShortcutManagerTest10
Test: atest CtsShortcutHostTestCases CtsShortcutManagerTestCases

Bug: 111698461
Change-Id: I92f27c81913ba6dfa57477e9c8df3e4e04b8664f
parent 72efe39d
Loading
Loading
Loading
Loading
+3 −0
Original line number Original line Diff line number Diff line
@@ -11917,6 +11917,9 @@ package android.content.pm {
    method public android.content.pm.ShortcutInfo.Builder setIntent(android.content.Intent);
    method public android.content.pm.ShortcutInfo.Builder setIntent(android.content.Intent);
    method public android.content.pm.ShortcutInfo.Builder setIntents(android.content.Intent[]);
    method public android.content.pm.ShortcutInfo.Builder setIntents(android.content.Intent[]);
    method public android.content.pm.ShortcutInfo.Builder setLongLabel(java.lang.CharSequence);
    method public android.content.pm.ShortcutInfo.Builder setLongLabel(java.lang.CharSequence);
    method public android.content.pm.ShortcutInfo.Builder setLongLived();
    method public android.content.pm.ShortcutInfo.Builder setPerson(android.app.Person);
    method public android.content.pm.ShortcutInfo.Builder setPersons(android.app.Person[]);
    method public android.content.pm.ShortcutInfo.Builder setRank(int);
    method public android.content.pm.ShortcutInfo.Builder setRank(int);
    method public android.content.pm.ShortcutInfo.Builder setShortLabel(java.lang.CharSequence);
    method public android.content.pm.ShortcutInfo.Builder setShortLabel(java.lang.CharSequence);
  }
  }
+114 −0
Original line number Original line Diff line number Diff line
@@ -21,6 +21,7 @@ import android.annotation.Nullable;
import android.annotation.TestApi;
import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
import android.annotation.UnsupportedAppUsage;
import android.annotation.UserIdInt;
import android.annotation.UserIdInt;
import android.app.Person;
import android.app.TaskStackBuilder;
import android.app.TaskStackBuilder;
import android.content.ComponentName;
import android.content.ComponentName;
import android.content.Context;
import android.content.Context;
@@ -110,6 +111,9 @@ public final class ShortcutInfo implements Parcelable {
     */
     */
    public static final int FLAG_SHADOW = 1 << 12;
    public static final int FLAG_SHADOW = 1 << 12;


    /** @hide */
    public static final int FLAG_LONG_LIVED = 1 << 13;

    /** @hide */
    /** @hide */
    @IntDef(flag = true, prefix = { "FLAG_" }, value = {
    @IntDef(flag = true, prefix = { "FLAG_" }, value = {
            FLAG_DYNAMIC,
            FLAG_DYNAMIC,
@@ -124,6 +128,8 @@ public final class ShortcutInfo implements Parcelable {
            FLAG_ADAPTIVE_BITMAP,
            FLAG_ADAPTIVE_BITMAP,
            FLAG_RETURNED_BY_SERVICE,
            FLAG_RETURNED_BY_SERVICE,
            FLAG_ICON_FILE_PENDING_SAVE,
            FLAG_ICON_FILE_PENDING_SAVE,
            FLAG_SHADOW,
            FLAG_LONG_LIVED,
    })
    })
    @Retention(RetentionPolicy.SOURCE)
    @Retention(RetentionPolicy.SOURCE)
    public @interface ShortcutFlags {}
    public @interface ShortcutFlags {}
@@ -344,6 +350,9 @@ public final class ShortcutInfo implements Parcelable {
    @Nullable
    @Nullable
    private PersistableBundle[] mIntentPersistableExtrases;
    private PersistableBundle[] mIntentPersistableExtrases;


    @Nullable
    private Person[] mPersons;

    private int mRank;
    private int mRank;


    /**
    /**
@@ -399,6 +408,10 @@ public final class ShortcutInfo implements Parcelable {
        mCategories = cloneCategories(b.mCategories);
        mCategories = cloneCategories(b.mCategories);
        mIntents = cloneIntents(b.mIntents);
        mIntents = cloneIntents(b.mIntents);
        fixUpIntentExtras();
        fixUpIntentExtras();
        mPersons = clonePersons(b.mPersons);
        if (b.mIsLongLived) {
            setLongLived();
        }
        mRank = b.mRank;
        mRank = b.mRank;
        mExtras = b.mExtras;
        mExtras = b.mExtras;
        updateTimestamp();
        updateTimestamp();
@@ -465,6 +478,20 @@ public final class ShortcutInfo implements Parcelable {
        return ret;
        return ret;
    }
    }


    private static Person[] clonePersons(Person[] persons) {
        if (persons == null) {
            return null;
        }
        final Person[] ret = new Person[persons.length];
        for (int i = 0; i < ret.length; i++) {
            if (persons[i] != null) {
                // Don't need to keep the icon, remove it to save space
                ret[i] = persons[i].toBuilder().setIcon(null).build();
            }
        }
        return ret;
    }

    /**
    /**
     * Throws if any of the mandatory fields is not set.
     * Throws if any of the mandatory fields is not set.
     *
     *
@@ -511,6 +538,7 @@ public final class ShortcutInfo implements Parcelable {
            mDisabledMessage = source.mDisabledMessage;
            mDisabledMessage = source.mDisabledMessage;
            mDisabledMessageResId = source.mDisabledMessageResId;
            mDisabledMessageResId = source.mDisabledMessageResId;
            mCategories = cloneCategories(source.mCategories);
            mCategories = cloneCategories(source.mCategories);
            mPersons = clonePersons(source.mPersons);
            if ((cloneFlags & CLONE_REMOVE_INTENT) == 0) {
            if ((cloneFlags & CLONE_REMOVE_INTENT) == 0) {
                mIntents = cloneIntents(source.mIntents);
                mIntents = cloneIntents(source.mIntents);
                mIntentPersistableExtrases =
                mIntentPersistableExtrases =
@@ -833,6 +861,9 @@ public final class ShortcutInfo implements Parcelable {
        if (source.mCategories != null) {
        if (source.mCategories != null) {
            mCategories = cloneCategories(source.mCategories);
            mCategories = cloneCategories(source.mCategories);
        }
        }
        if (source.mPersons != null) {
            mPersons = clonePersons(source.mPersons);
        }
        if (source.mIntents != null) {
        if (source.mIntents != null) {
            mIntents = cloneIntents(source.mIntents);
            mIntents = cloneIntents(source.mIntents);
            mIntentPersistableExtrases =
            mIntentPersistableExtrases =
@@ -901,6 +932,10 @@ public final class ShortcutInfo implements Parcelable {


        private Intent[] mIntents;
        private Intent[] mIntents;


        private Person[] mPersons;

        private boolean mIsLongLived;

        private int mRank = RANK_NOT_SET;
        private int mRank = RANK_NOT_SET;


        private PersistableBundle mExtras;
        private PersistableBundle mExtras;
@@ -1164,6 +1199,53 @@ public final class ShortcutInfo implements Parcelable {
            return this;
            return this;
        }
        }


        /**
         * Add a person that is relevant to this shortcut. Alternatively,
         * {@link #setPersons(Person[])} can be used to add multiple persons to a shortcut.
         *
         * <p> This is an optional field, but the addition of person may cause this shortcut to
         * appear more prominently in the user interface (e.g. ShareSheet).
         *
         * <p> A person should usually contain a uri in order to benefit from the ranking boost.
         * However, even if no uri is provided, it's beneficial to provide people in the shortcut,
         * such that listeners and voice only devices can announce and handle them properly.
         *
         * @see Person
         * @see #setPersons(Person[])
         */
        @NonNull
        public Builder setPerson(@NonNull Person person) {
            return setPersons(new Person[]{person});
        }

        /**
         * Sets multiple persons instead of a single person.
         *
         * @see Person
         * @see #setPerson(Person)
         */
        @NonNull
        public Builder setPersons(@NonNull Person[] persons) {
            Preconditions.checkNotNull(persons, "persons cannot be null");
            Preconditions.checkNotNull(persons.length, "persons cannot be empty");
            for (Person person : persons) {
                Preconditions.checkNotNull(person, "persons cannot contain null");
            }
            mPersons = clonePersons(persons);
            return this;
        }

        /**
         * Sets if a shortcut would be valid even if it has been unpublished/invisible by the app
         * (as a dynamic or pinned shortcut). If it is long lived, it can be cached by various
         * system services even after it has been unpublished as a dynamic shortcut.
         */
        @NonNull
        public Builder setLongLived() {
            mIsLongLived = true;
            return this;
        }

        /**
        /**
         * "Rank" of a shortcut, which is a non-negative value that's used by the launcher app
         * "Rank" of a shortcut, which is a non-negative value that's used by the launcher app
         * to sort shortcuts.
         * to sort shortcuts.
@@ -1394,6 +1476,16 @@ public final class ShortcutInfo implements Parcelable {
        return mIntents;
        return mIntents;
    }
    }


    /**
     * Return the Persons set with {@link Builder#setPersons(Person[])}.
     *
     * @hide
     */
    @Nullable
    public Person[] getPersons() {
        return clonePersons(mPersons);
    }

    /**
    /**
     * The extras in the intents.  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.
     * persist them.
@@ -1525,6 +1617,16 @@ public final class ShortcutInfo implements Parcelable {
        addFlags(FLAG_RETURNED_BY_SERVICE);
        addFlags(FLAG_RETURNED_BY_SERVICE);
    }
    }


    /** @hide */
    public boolean isLongLived() {
        return hasFlags(FLAG_LONG_LIVED);
    }

    /** @hide */
    public void setLongLived() {
        addFlags(FLAG_LONG_LIVED);
    }

    /** Return whether a shortcut is dynamic. */
    /** Return whether a shortcut is dynamic. */
    public boolean isDynamic() {
    public boolean isDynamic() {
        return hasFlags(FLAG_DYNAMIC);
        return hasFlags(FLAG_DYNAMIC);
@@ -1893,6 +1995,8 @@ public final class ShortcutInfo implements Parcelable {
                mCategories.add(source.readString().intern());
                mCategories.add(source.readString().intern());
            }
            }
        }
        }

        mPersons = source.readParcelableArray(cl, Person.class);
    }
    }


    @Override
    @Override
@@ -1940,6 +2044,8 @@ public final class ShortcutInfo implements Parcelable {
        } else {
        } else {
            dest.writeInt(0);
            dest.writeInt(0);
        }
        }

        dest.writeParcelableArray(mPersons, flags);
    }
    }


    public static final Creator<ShortcutInfo> CREATOR =
    public static final Creator<ShortcutInfo> CREATOR =
@@ -2040,6 +2146,9 @@ public final class ShortcutInfo implements Parcelable {
        if (isReturnedByServer()) {
        if (isReturnedByServer()) {
            sb.append("Rets");
            sb.append("Rets");
        }
        }
        if (isLongLived()) {
            sb.append("Liv");
        }
        sb.append("]");
        sb.append("]");


        addIndentOrComma(sb, indent);
        addIndentOrComma(sb, indent);
@@ -2094,6 +2203,11 @@ public final class ShortcutInfo implements Parcelable {


        addIndentOrComma(sb, indent);
        addIndentOrComma(sb, indent);


        sb.append("persons=");
        sb.append(mPersons);

        addIndentOrComma(sb, indent);

        sb.append("icon=");
        sb.append("icon=");
        sb.append(mIcon);
        sb.append(mIcon);


+9 −0
Original line number Original line Diff line number Diff line
@@ -42,6 +42,7 @@ import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.ActivityManagerInternal;
import android.app.IUidObserver;
import android.app.IUidObserver;
import android.app.Person;
import android.app.usage.UsageStatsManagerInternal;
import android.app.usage.UsageStatsManagerInternal;
import android.content.ActivityNotFoundException;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.BroadcastReceiver;
@@ -1587,6 +1588,14 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
        return intent;
        return intent;
    }
    }


    /**
     * Make a Person.
     */
    protected Person makePerson(CharSequence name, String key, String uri) {
        final Person.Builder builder = new Person.Builder();
        return builder.setName(name).setKey(key).setUri(uri).build();
    }

    /**
    /**
     * Make an component name, with the client context.
     * Make an component name, with the client context.
     */
     */
+29 −5
Original line number Original line Diff line number Diff line
@@ -248,6 +248,8 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest {
                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
                .setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
                .setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
                .setRank(123)
                .setRank(123)
                .setPerson(makePerson("person", "personKey", "personUri"))
                .setLongLived()
                .setExtras(pb)
                .setExtras(pb)
                .build();
                .build();
        si.addFlags(ShortcutInfo.FLAG_PINNED);
        si.addFlags(ShortcutInfo.FLAG_PINNED);
@@ -267,9 +269,12 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest {
        assertEquals("action", si.getIntent().getAction());
        assertEquals("action", si.getIntent().getAction());
        assertEquals("val", si.getIntent().getStringExtra("key"));
        assertEquals("val", si.getIntent().getStringExtra("key"));
        assertEquals(123, si.getRank());
        assertEquals(123, si.getRank());
        assertEquals("person", si.getPersons()[0].getName());
        assertEquals("personKey", si.getPersons()[0].getKey());
        assertEquals("personUri", si.getPersons()[0].getUri());
        assertEquals(1, si.getExtras().getInt("k"));
        assertEquals(1, si.getExtras().getInt("k"));


        assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
        assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_LONG_LIVED, si.getFlags());
        assertEquals("abc", si.getBitmapPath());
        assertEquals("abc", si.getBitmapPath());
        assertEquals(456, si.getIconResourceId());
        assertEquals(456, si.getIconResourceId());


@@ -345,6 +350,8 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest {
                .setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
                .setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
                .setRank(123)
                .setRank(123)
                .setPerson(makePerson("person", "personKey", "personUri"))
                .setLongLived()
                .setExtras(pb)
                .setExtras(pb)
                .build();
                .build();
        sorig.addFlags(ShortcutInfo.FLAG_PINNED);
        sorig.addFlags(ShortcutInfo.FLAG_PINNED);
@@ -368,9 +375,12 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest {
        assertEquals("action", si.getIntent().getAction());
        assertEquals("action", si.getIntent().getAction());
        assertEquals("val", si.getIntent().getStringExtra("key"));
        assertEquals("val", si.getIntent().getStringExtra("key"));
        assertEquals(123, si.getRank());
        assertEquals(123, si.getRank());
        assertEquals("person", si.getPersons()[0].getName());
        assertEquals("personKey", si.getPersons()[0].getKey());
        assertEquals("personUri", si.getPersons()[0].getUri());
        assertEquals(1, si.getExtras().getInt("k"));
        assertEquals(1, si.getExtras().getInt("k"));


        assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
        assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_LONG_LIVED, si.getFlags());
        assertEquals("abc", si.getBitmapPath());
        assertEquals("abc", si.getBitmapPath());
        assertEquals(456, si.getIconResourceId());
        assertEquals(456, si.getIconResourceId());
        assertEquals("string/r456", si.getIconResName());
        assertEquals("string/r456", si.getIconResName());
@@ -388,9 +398,12 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest {
        assertEquals("action", si.getIntent().getAction());
        assertEquals("action", si.getIntent().getAction());
        assertEquals("val", si.getIntent().getStringExtra("key"));
        assertEquals("val", si.getIntent().getStringExtra("key"));
        assertEquals(123, si.getRank());
        assertEquals(123, si.getRank());
        assertEquals("person", si.getPersons()[0].getName());
        assertEquals("personKey", si.getPersons()[0].getKey());
        assertEquals("personUri", si.getPersons()[0].getUri());
        assertEquals(1, si.getExtras().getInt("k"));
        assertEquals(1, si.getExtras().getInt("k"));


        assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
        assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_LONG_LIVED, si.getFlags());
        assertEquals(null, si.getBitmapPath());
        assertEquals(null, si.getBitmapPath());


        assertEquals(456, si.getIconResourceId());
        assertEquals(456, si.getIconResourceId());
@@ -408,9 +421,12 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest {
        assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
        assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
        assertEquals(null, si.getIntent());
        assertEquals(null, si.getIntent());
        assertEquals(123, si.getRank());
        assertEquals(123, si.getRank());
        assertEquals("person", si.getPersons()[0].getName());
        assertEquals("personKey", si.getPersons()[0].getKey());
        assertEquals("personUri", si.getPersons()[0].getUri());
        assertEquals(1, si.getExtras().getInt("k"));
        assertEquals(1, si.getExtras().getInt("k"));


        assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
        assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_LONG_LIVED, si.getFlags());
        assertEquals(null, si.getBitmapPath());
        assertEquals(null, si.getBitmapPath());


        assertEquals(456, si.getIconResourceId());
        assertEquals(456, si.getIconResourceId());
@@ -428,9 +444,11 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest {
        assertEquals(null, si.getCategories());
        assertEquals(null, si.getCategories());
        assertEquals(null, si.getIntent());
        assertEquals(null, si.getIntent());
        assertEquals(0, si.getRank());
        assertEquals(0, si.getRank());
        assertEquals(null, si.getPersons());
        assertEquals(null, si.getExtras());
        assertEquals(null, si.getExtras());


        assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_KEY_FIELDS_ONLY, si.getFlags());
        assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_KEY_FIELDS_ONLY
                | ShortcutInfo.FLAG_LONG_LIVED, si.getFlags());
        assertEquals(null, si.getBitmapPath());
        assertEquals(null, si.getBitmapPath());


        assertEquals(456, si.getIconResourceId());
        assertEquals(456, si.getIconResourceId());
@@ -690,6 +708,12 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest {
        assertEquals("text", si.getText());
        assertEquals("text", si.getText());
        assertEquals(set("x"), si.getCategories());
        assertEquals(set("x"), si.getCategories());


        si = sorig.clone(/* flags=*/ 0);
        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
                .setPerson(makePerson("person", "", "")).build());
        assertEquals("text", si.getText());
        assertEquals("person", si.getPersons()[0].getName());

        si = sorig.clone(/* flags=*/ 0);
        si = sorig.clone(/* flags=*/ 0);
        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
                .setIntent(makeIntent("action2", ShortcutActivity.class)).build());
                .setIntent(makeIntent("action2", ShortcutActivity.class)).build());