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

Commit e7238dd1 authored by Selim Cinek's avatar Selim Cinek
Browse files

Added People to the Notification API

In order to support people without a URI and further
changes in MessagingStyle, a new person API is
introduced that allows for a richer presentation.
In addition are we now properly supporting people
without a URI, which is useful for non-handheld
clients

Test: runtest -x tests/app/src/android/app/cts/NotificationTest.java
Bug: 63708826
Change-Id: I496c893273803a2ec4fd3a5b731a6b4d483801ea
parent 0be794a1
Loading
Loading
Loading
Loading
+20 −2
Original line number Original line Diff line number Diff line
@@ -5207,7 +5207,8 @@ package android.app {
    field public static final java.lang.String EXTRA_MESSAGES = "android.messages";
    field public static final java.lang.String EXTRA_MESSAGES = "android.messages";
    field public static final java.lang.String EXTRA_NOTIFICATION_ID = "android.intent.extra.NOTIFICATION_ID";
    field public static final java.lang.String EXTRA_NOTIFICATION_ID = "android.intent.extra.NOTIFICATION_ID";
    field public static final java.lang.String EXTRA_NOTIFICATION_TAG = "android.intent.extra.NOTIFICATION_TAG";
    field public static final java.lang.String EXTRA_NOTIFICATION_TAG = "android.intent.extra.NOTIFICATION_TAG";
    field public static final java.lang.String EXTRA_PEOPLE = "android.people";
    field public static final deprecated java.lang.String EXTRA_PEOPLE = "android.people";
    field public static final java.lang.String EXTRA_PEOPLE_LIST = "android.people.list";
    field public static final java.lang.String EXTRA_PICTURE = "android.picture";
    field public static final java.lang.String EXTRA_PICTURE = "android.picture";
    field public static final java.lang.String EXTRA_PROGRESS = "android.progress";
    field public static final java.lang.String EXTRA_PROGRESS = "android.progress";
    field public static final java.lang.String EXTRA_PROGRESS_INDETERMINATE = "android.progressIndeterminate";
    field public static final java.lang.String EXTRA_PROGRESS_INDETERMINATE = "android.progressIndeterminate";
@@ -5353,7 +5354,8 @@ package android.app {
    method public deprecated android.app.Notification.Builder addAction(int, java.lang.CharSequence, android.app.PendingIntent);
    method public deprecated android.app.Notification.Builder addAction(int, java.lang.CharSequence, android.app.PendingIntent);
    method public android.app.Notification.Builder addAction(android.app.Notification.Action);
    method public android.app.Notification.Builder addAction(android.app.Notification.Action);
    method public android.app.Notification.Builder addExtras(android.os.Bundle);
    method public android.app.Notification.Builder addExtras(android.os.Bundle);
    method public android.app.Notification.Builder addPerson(java.lang.String);
    method public deprecated android.app.Notification.Builder addPerson(java.lang.String);
    method public android.app.Notification.Builder addPerson(android.app.Notification.Person);
    method public android.app.Notification build();
    method public android.app.Notification build();
    method public android.widget.RemoteViews createBigContentView();
    method public android.widget.RemoteViews createBigContentView();
    method public android.widget.RemoteViews createContentView();
    method public android.widget.RemoteViews createContentView();
@@ -5501,6 +5503,22 @@ package android.app {
    method public android.app.Notification.MessagingStyle.Message setData(java.lang.String, android.net.Uri);
    method public android.app.Notification.MessagingStyle.Message setData(java.lang.String, android.net.Uri);
  }
  }
  public static final class Notification.Person implements android.os.Parcelable {
    ctor protected Notification.Person(android.os.Parcel);
    ctor public Notification.Person();
    method public int describeContents();
    method public android.graphics.drawable.Icon getIcon();
    method public java.lang.String getKey();
    method public java.lang.CharSequence getName();
    method public java.lang.String getUri();
    method public android.app.Notification.Person setIcon(android.graphics.drawable.Icon);
    method public android.app.Notification.Person setKey(java.lang.String);
    method public android.app.Notification.Person setName(java.lang.CharSequence);
    method public android.app.Notification.Person setUri(java.lang.String);
    method public void writeToParcel(android.os.Parcel, int);
    field public static final android.os.Parcelable.Creator<android.app.Notification.Person> CREATOR;
  }
  public static abstract class Notification.Style {
  public static abstract class Notification.Style {
    ctor public Notification.Style();
    ctor public Notification.Style();
    method public android.app.Notification build();
    method public android.app.Notification build();
+212 −6
Original line number Original line Diff line number Diff line
@@ -1022,9 +1022,17 @@ public class Notification implements Parcelable
    /**
    /**
     * {@link #extras} key: A String array containing the people that this notification relates to,
     * {@link #extras} key: A String array containing the people that this notification relates to,
     * each of which was supplied to {@link Builder#addPerson(String)}.
     * each of which was supplied to {@link Builder#addPerson(String)}.
     *
     * @deprecated the actual objects are now in {@link #EXTRA_PEOPLE_LIST}
     */
     */
    public static final String EXTRA_PEOPLE = "android.people";
    public static final String EXTRA_PEOPLE = "android.people";


    /**
     * {@link #extras} key: An arrayList of {@link Person} objects containing the people that
     * this notification relates to.
     */
    public static final String EXTRA_PEOPLE_LIST = "android.people.list";

    /**
    /**
     * Allow certain system-generated notifications to appear before the device is provisioned.
     * Allow certain system-generated notifications to appear before the device is provisioned.
     * Only available to notifications coming from the android package.
     * Only available to notifications coming from the android package.
@@ -2819,7 +2827,7 @@ public class Notification implements Parcelable
        private Bundle mUserExtras = new Bundle();
        private Bundle mUserExtras = new Bundle();
        private Style mStyle;
        private Style mStyle;
        private ArrayList<Action> mActions = new ArrayList<Action>(MAX_ACTION_BUTTONS);
        private ArrayList<Action> mActions = new ArrayList<Action>(MAX_ACTION_BUTTONS);
        private ArrayList<String> mPersonList = new ArrayList<String>();
        private ArrayList<Person> mPersonList = new ArrayList<>();
        private NotificationColorUtil mColorUtil;
        private NotificationColorUtil mColorUtil;
        private boolean mIsLegacy;
        private boolean mIsLegacy;
        private boolean mIsLegacyInitialized;
        private boolean mIsLegacyInitialized;
@@ -2910,8 +2918,9 @@ public class Notification implements Parcelable
                    Collections.addAll(mActions, mN.actions);
                    Collections.addAll(mActions, mN.actions);
                }
                }


                if (mN.extras.containsKey(EXTRA_PEOPLE)) {
                if (mN.extras.containsKey(EXTRA_PEOPLE_LIST)) {
                    Collections.addAll(mPersonList, mN.extras.getStringArray(EXTRA_PEOPLE));
                    ArrayList<Person> people = mN.extras.getParcelableArrayList(EXTRA_PEOPLE_LIST);
                    mPersonList.addAll(people);
                }
                }


                if (mN.getSmallIcon() == null && mN.icon != 0) {
                if (mN.getSmallIcon() == null && mN.icon != 0) {
@@ -3621,13 +3630,41 @@ public class Notification implements Parcelable
         * URIs.  The path part of these URIs must exist in the contacts database, in the
         * URIs.  The path part of these URIs must exist in the contacts database, in the
         * appropriate column, or the reference will be discarded as invalid. Telephone schema
         * appropriate column, or the reference will be discarded as invalid. Telephone schema
         * URIs will be resolved by {@link android.provider.ContactsContract.PhoneLookup}.
         * URIs will be resolved by {@link android.provider.ContactsContract.PhoneLookup}.
         * It is also possible to provide a URI with the schema {@code name:} in order to uniquely
         * identify a person without an entry in the contacts database.
         * </P>
         * </P>
         *
         *
         * @param uri A URI for the person.
         * @param uri A URI for the person.
         * @see Notification#EXTRA_PEOPLE
         * @see Notification#EXTRA_PEOPLE
         * @deprecated use {@link #addPerson(Person)}
         */
         */
        public Builder addPerson(String uri) {
        public Builder addPerson(String uri) {
            mPersonList.add(uri);
            addPerson(new Person().setUri(uri));
            return this;
        }

        /**
         * Add a person that is relevant to this notification.
         *
         * <P>
         * Depending on user preferences, this annotation may allow the notification to pass
         * through interruption filters, if this notification is of category {@link #CATEGORY_CALL}
         * or {@link #CATEGORY_MESSAGE}. The addition of people may also cause this notification to
         * appear more prominently in the user interface.
         * </P>
         *
         * <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 other people in the
         * notification, such that listeners and voice only devices can announce and handle them
         * properly.
         * </P>
         *
         * @param person the person to add.
         * @see Notification#EXTRA_PEOPLE_LIST
         */
        public Builder addPerson(Person person) {
            mPersonList.add(person);
            return this;
            return this;
        }
        }


@@ -4968,8 +5005,7 @@ public class Notification implements Parcelable
                mActions.toArray(mN.actions);
                mActions.toArray(mN.actions);
            }
            }
            if (!mPersonList.isEmpty()) {
            if (!mPersonList.isEmpty()) {
                mN.extras.putStringArray(EXTRA_PEOPLE,
                mN.extras.putParcelableArrayList(EXTRA_PEOPLE_LIST, mPersonList);
                        mPersonList.toArray(new String[mPersonList.size()]));
            }
            }
            if (mN.bigContentView != null || mN.contentView != null
            if (mN.bigContentView != null || mN.contentView != null
                    || mN.headsUpContentView != null) {
                    || mN.headsUpContentView != null) {
@@ -7102,6 +7138,176 @@ public class Notification implements Parcelable
        }
        }
    }
    }


    /**
     * A Person associated with this Notification.
     */
    public static final class Person implements Parcelable {
        @Nullable private CharSequence mName;
        @Nullable private Icon mIcon;
        @Nullable private String mUri;
        @Nullable private String mKey;

        protected Person(Parcel in) {
            mName = in.readCharSequence();
            if (in.readInt() != 0) {
                mIcon = Icon.CREATOR.createFromParcel(in);
            }
            mUri = in.readString();
            mKey = in.readString();
        }

        /**
         * Create a new person.
         */
        public Person() {
        }

        /**
         * Give this person a name.
         *
         * @param name the name of this person
         */
        public Person setName(@Nullable CharSequence name) {
            this.mName = name;
            return this;
        }

        /**
         * Add an icon for this person.
         * <br />
         * This is currently only used for {@link MessagingStyle} notifications and should not be
         * provided otherwise, in order to save memory. The system will prefer this icon over any
         * images that are resolved from the URI.
         *
         * @param icon the icon of the person
         */
        public Person setIcon(@Nullable Icon icon) {
            this.mIcon = icon;
            return this;
        }

        /**
         * Set a URI associated with this person.
         *
         * <P>
         * Depending on user preferences, adding a URI to a Person may allow the notification to
         * pass through interruption filters, if this notification is of
         * category {@link #CATEGORY_CALL} or {@link #CATEGORY_MESSAGE}.
         * The addition of people may also cause this notification to appear more prominently in
         * the user interface.
         * </P>
         *
         * <P>
         * The person should be specified by the {@code String} representation of a
         * {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI}.
         * </P>
         *
         * <P>The system will also attempt to resolve {@code mailto:} and {@code tel:} schema
         * URIs.  The path part of these URIs must exist in the contacts database, in the
         * appropriate column, or the reference will be discarded as invalid. Telephone schema
         * URIs will be resolved by {@link android.provider.ContactsContract.PhoneLookup}.
         * </P>
         *
         * @param uri a URI for the person
         */
        public Person setUri(@Nullable String uri) {
            mUri = uri;
            return this;
        }

        /**
         * Add a key to this person in order to uniquely identify it.
         * This is especially useful if the name doesn't uniquely identify this person or if the
         * display name is a short handle of the actual name.
         *
         * <P>If no key is provided, the name serves as as the key for the purpose of
         * identification.</P>
         *
         * @param key the key that uniquely identifies this person
         */
        public Person setKey(@Nullable String key) {
            mKey = key;
            return this;
        }


        /**
         * @return the uri provided for this person or {@code null} if no Uri was provided
         */
        @Nullable
        public String getUri() {
            return mUri;
        }

        /**
         * @return the name provided for this person or {@code null} if no name was provided
         */
        @Nullable
        public CharSequence getName() {
            return mName;
        }

        /**
         * @return the icon provided for this person or {@code null} if no icon was provided
         */
        @Nullable
        public Icon getIcon() {
            return mIcon;
        }

        /**
         * @return the key provided for this person or {@code null} if no key was provided
         */
        @Nullable
        public String getKey() {
            return mKey;
        }

        /**
         * @return the URI associated with this person, or "name:mName" otherwise
         *  @hide
         */
        public String resolveToLegacyUri() {
            if (mUri != null) {
                return mUri;
            }
            if (mName != null) {
                return "name:" + mName;
            }
            return "";
        }

        @Override
        public int describeContents() {
            return 0;
        }

        @Override
        public void writeToParcel(Parcel dest, @WriteFlags int flags) {
            dest.writeCharSequence(mName);
            if (mIcon != null) {
                dest.writeInt(1);
                mIcon.writeToParcel(dest, 0);
            } else {
                dest.writeInt(0);
            }
            dest.writeString(mUri);
            dest.writeString(mKey);
        }

        public static final Creator<Person> CREATOR = new Creator<Person>() {
            @Override
            public Person createFromParcel(Parcel in) {
                return new Person(in);
            }

            @Override
            public Person[] newArray(int size) {
                return new Person[size];
            }
        };
    }

    // When adding a new Style subclass here, don't forget to update
    // When adding a new Style subclass here, don't forget to update
    // Builder.getNotificationStyleClass.
    // Builder.getNotificationStyleClass.


+21 −0
Original line number Original line Diff line number Diff line
@@ -890,6 +890,8 @@ public abstract class NotificationListenerService extends Service {
                createLegacyIconExtras(notification);
                createLegacyIconExtras(notification);
                // populate remote views for older clients.
                // populate remote views for older clients.
                maybePopulateRemoteViews(notification);
                maybePopulateRemoteViews(notification);
                // populate people for older clients.
                maybePopulatePeople(notification);
            } catch (IllegalArgumentException e) {
            } catch (IllegalArgumentException e) {
                if (corruptNotifications == null) {
                if (corruptNotifications == null) {
                    corruptNotifications = new ArrayList<>(N);
                    corruptNotifications = new ArrayList<>(N);
@@ -1178,6 +1180,25 @@ public abstract class NotificationListenerService extends Service {
        }
        }
    }
    }


    /**
     * Populates remote views for pre-P targeting apps.
     */
    private void maybePopulatePeople(Notification notification) {
        if (getContext().getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.P) {
            ArrayList<Notification.Person> people = notification.extras.getParcelableArrayList(
                    Notification.EXTRA_PEOPLE_LIST);
            if (people != null && people.isEmpty()) {
                int size = people.size();
                String[] peopleArray = new String[size];
                for (int i = 0; i < size; i++) {
                    Notification.Person person = people.get(i);
                    peopleArray[i] = person.resolveToLegacyUri();
                }
                notification.extras.putStringArray(Notification.EXTRA_PEOPLE, peopleArray);
            }
        }
    }

    /** @hide */
    /** @hide */
    protected class NotificationListenerWrapper extends INotificationListener.Stub {
    protected class NotificationListenerWrapper extends INotificationListener.Stub {
        @Override
        @Override
+14 −2
Original line number Original line Diff line number Diff line
@@ -278,7 +278,7 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor {


    // VisibleForTesting
    // VisibleForTesting
    public static String[] getExtraPeople(Bundle extras) {
    public static String[] getExtraPeople(Bundle extras) {
        Object people = extras.get(Notification.EXTRA_PEOPLE);
        Object people = extras.get(Notification.EXTRA_PEOPLE_LIST);
        if (people instanceof String[]) {
        if (people instanceof String[]) {
            return (String[]) people;
            return (String[]) people;
        }
        }
@@ -305,6 +305,16 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor {
                return array;
                return array;
            }
            }


            if (arrayList.get(0) instanceof Notification.Person) {
                ArrayList<Notification.Person> list = (ArrayList<Notification.Person>) arrayList;
                final int N = list.size();
                String[] array = new String[N];
                for (int i = 0; i < N; i++) {
                    array[i] = list.get(i).resolveToLegacyUri();
                }
                return array;
            }

            return null;
            return null;
        }
        }


@@ -459,8 +469,10 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor {
                    lookupResult = searchContacts(mContext, uri);
                    lookupResult = searchContacts(mContext, uri);
                } else {
                } else {
                    lookupResult = new LookupResult();  // invalid person for the cache
                    lookupResult = new LookupResult();  // invalid person for the cache
                    if (!"name".equals(uri.getScheme())) {
                        Slog.w(TAG, "unsupported URI " + handle);
                        Slog.w(TAG, "unsupported URI " + handle);
                    }
                    }
                }
                if (lookupResult != null) {
                if (lookupResult != null) {
                    synchronized (mPeopleCache) {
                    synchronized (mPeopleCache) {
                        final String cacheKey = getCacheKey(mContext.getUserId(), handle);
                        final String cacheKey = getCacheKey(mContext.getUserId(), handle);
+23 −10
Original line number Original line Diff line number Diff line
@@ -47,7 +47,7 @@ public class ValidateNotificationPeopleTest extends UiServiceTestCase {
    public void testSingleString() throws Exception {
    public void testSingleString() throws Exception {
        String[] expected = { "foobar" };
        String[] expected = { "foobar" };
        Bundle bundle = new Bundle();
        Bundle bundle = new Bundle();
        bundle.putString(Notification.EXTRA_PEOPLE, expected[0]);
        bundle.putString(Notification.EXTRA_PEOPLE_LIST, expected[0]);
        String[] result = ValidateNotificationPeople.getExtraPeople(bundle);
        String[] result = ValidateNotificationPeople.getExtraPeople(bundle);
        assertStringArrayEquals("string should be in result[0]", expected, result);
        assertStringArrayEquals("string should be in result[0]", expected, result);
    }
    }
@@ -56,7 +56,7 @@ public class ValidateNotificationPeopleTest extends UiServiceTestCase {
    public void testSingleCharArray() throws Exception {
    public void testSingleCharArray() throws Exception {
        String[] expected = { "foobar" };
        String[] expected = { "foobar" };
        Bundle bundle = new Bundle();
        Bundle bundle = new Bundle();
        bundle.putCharArray(Notification.EXTRA_PEOPLE, expected[0].toCharArray());
        bundle.putCharArray(Notification.EXTRA_PEOPLE_LIST, expected[0].toCharArray());
        String[] result = ValidateNotificationPeople.getExtraPeople(bundle);
        String[] result = ValidateNotificationPeople.getExtraPeople(bundle);
        assertStringArrayEquals("char[] should be in result[0]", expected, result);
        assertStringArrayEquals("char[] should be in result[0]", expected, result);
    }
    }
@@ -65,7 +65,7 @@ public class ValidateNotificationPeopleTest extends UiServiceTestCase {
    public void testSingleCharSequence() throws Exception {
    public void testSingleCharSequence() throws Exception {
        String[] expected = { "foobar" };
        String[] expected = { "foobar" };
        Bundle bundle = new Bundle();
        Bundle bundle = new Bundle();
        bundle.putCharSequence(Notification.EXTRA_PEOPLE, new SpannableString(expected[0]));
        bundle.putCharSequence(Notification.EXTRA_PEOPLE_LIST, new SpannableString(expected[0]));
        String[] result = ValidateNotificationPeople.getExtraPeople(bundle);
        String[] result = ValidateNotificationPeople.getExtraPeople(bundle);
        assertStringArrayEquals("charSequence should be in result[0]", expected, result);
        assertStringArrayEquals("charSequence should be in result[0]", expected, result);
    }
    }
@@ -74,7 +74,7 @@ public class ValidateNotificationPeopleTest extends UiServiceTestCase {
    public void testStringArraySingle() throws Exception {
    public void testStringArraySingle() throws Exception {
        Bundle bundle = new Bundle();
        Bundle bundle = new Bundle();
        String[] expected = { "foobar" };
        String[] expected = { "foobar" };
        bundle.putStringArray(Notification.EXTRA_PEOPLE, expected);
        bundle.putStringArray(Notification.EXTRA_PEOPLE_LIST, expected);
        String[] result = ValidateNotificationPeople.getExtraPeople(bundle);
        String[] result = ValidateNotificationPeople.getExtraPeople(bundle);
        assertStringArrayEquals("wrapped string should be in result[0]", expected, result);
        assertStringArrayEquals("wrapped string should be in result[0]", expected, result);
    }
    }
@@ -83,7 +83,7 @@ public class ValidateNotificationPeopleTest extends UiServiceTestCase {
    public void testStringArrayMultiple() throws Exception {
    public void testStringArrayMultiple() throws Exception {
        Bundle bundle = new Bundle();
        Bundle bundle = new Bundle();
        String[] expected = { "foo", "bar", "baz" };
        String[] expected = { "foo", "bar", "baz" };
        bundle.putStringArray(Notification.EXTRA_PEOPLE, expected);
        bundle.putStringArray(Notification.EXTRA_PEOPLE_LIST, expected);
        String[] result = ValidateNotificationPeople.getExtraPeople(bundle);
        String[] result = ValidateNotificationPeople.getExtraPeople(bundle);
        assertStringArrayEquals("testStringArrayMultiple", expected, result);
        assertStringArrayEquals("testStringArrayMultiple", expected, result);
    }
    }
@@ -92,7 +92,7 @@ public class ValidateNotificationPeopleTest extends UiServiceTestCase {
    public void testStringArrayNulls() throws Exception {
    public void testStringArrayNulls() throws Exception {
        Bundle bundle = new Bundle();
        Bundle bundle = new Bundle();
        String[] expected = { "foo", null, "baz" };
        String[] expected = { "foo", null, "baz" };
        bundle.putStringArray(Notification.EXTRA_PEOPLE, expected);
        bundle.putStringArray(Notification.EXTRA_PEOPLE_LIST, expected);
        String[] result = ValidateNotificationPeople.getExtraPeople(bundle);
        String[] result = ValidateNotificationPeople.getExtraPeople(bundle);
        assertStringArrayEquals("testStringArrayNulls", expected, result);
        assertStringArrayEquals("testStringArrayNulls", expected, result);
    }
    }
@@ -105,7 +105,7 @@ public class ValidateNotificationPeopleTest extends UiServiceTestCase {
        for (int i = 0; i < expected.length; i++) {
        for (int i = 0; i < expected.length; i++) {
            charSeqArray[i] = new SpannableString(expected[i]);
            charSeqArray[i] = new SpannableString(expected[i]);
        }
        }
        bundle.putCharSequenceArray(Notification.EXTRA_PEOPLE, charSeqArray);
        bundle.putCharSequenceArray(Notification.EXTRA_PEOPLE_LIST, charSeqArray);
        String[] result = ValidateNotificationPeople.getExtraPeople(bundle);
        String[] result = ValidateNotificationPeople.getExtraPeople(bundle);
        assertStringArrayEquals("testCharSequenceArrayMultiple", expected, result);
        assertStringArrayEquals("testCharSequenceArrayMultiple", expected, result);
    }
    }
@@ -122,7 +122,7 @@ public class ValidateNotificationPeopleTest extends UiServiceTestCase {
                charSeqArray[i] = new SpannableString(expected[i]);
                charSeqArray[i] = new SpannableString(expected[i]);
            }
            }
        }
        }
        bundle.putCharSequenceArray(Notification.EXTRA_PEOPLE, charSeqArray);
        bundle.putCharSequenceArray(Notification.EXTRA_PEOPLE_LIST, charSeqArray);
        String[] result = ValidateNotificationPeople.getExtraPeople(bundle);
        String[] result = ValidateNotificationPeople.getExtraPeople(bundle);
        assertStringArrayEquals("testMixedCharSequenceArrayList", expected, result);
        assertStringArrayEquals("testMixedCharSequenceArrayList", expected, result);
    }
    }
@@ -135,7 +135,7 @@ public class ValidateNotificationPeopleTest extends UiServiceTestCase {
        for (int i = 0; i < expected.length; i++) {
        for (int i = 0; i < expected.length; i++) {
            stringArrayList.add(expected[i]);
            stringArrayList.add(expected[i]);
        }
        }
        bundle.putStringArrayList(Notification.EXTRA_PEOPLE, stringArrayList);
        bundle.putStringArrayList(Notification.EXTRA_PEOPLE_LIST, stringArrayList);
        String[] result = ValidateNotificationPeople.getExtraPeople(bundle);
        String[] result = ValidateNotificationPeople.getExtraPeople(bundle);
        assertStringArrayEquals("testStringArrayList", expected, result);
        assertStringArrayEquals("testStringArrayList", expected, result);
    }
    }
@@ -149,11 +149,24 @@ public class ValidateNotificationPeopleTest extends UiServiceTestCase {
        for (int i = 0; i < expected.length; i++) {
        for (int i = 0; i < expected.length; i++) {
            stringArrayList.add(new SpannableString(expected[i]));
            stringArrayList.add(new SpannableString(expected[i]));
        }
        }
        bundle.putCharSequenceArrayList(Notification.EXTRA_PEOPLE, stringArrayList);
        bundle.putCharSequenceArrayList(Notification.EXTRA_PEOPLE_LIST, stringArrayList);
        String[] result = ValidateNotificationPeople.getExtraPeople(bundle);
        String[] result = ValidateNotificationPeople.getExtraPeople(bundle);
        assertStringArrayEquals("testCharSequenceArrayList", expected, result);
        assertStringArrayEquals("testCharSequenceArrayList", expected, result);
    }
    }


    @Test
    public void testPeopleArrayList() throws Exception {
        Bundle bundle = new Bundle();
        String[] expected = { "name:test" , "tel:1234" };
        final ArrayList<Notification.Person> arrayList =
                new ArrayList<>(expected.length);
        arrayList.add(new Notification.Person().setName("test"));
        arrayList.add(new Notification.Person().setUri(expected[1]));
        bundle.putParcelableArrayList(Notification.EXTRA_PEOPLE_LIST, arrayList);
        String[] result = ValidateNotificationPeople.getExtraPeople(bundle);
        assertStringArrayEquals("testPeopleArrayList", expected, result);
    }

    private void assertStringArrayEquals(String message, String[] expected, String[] result) {
    private void assertStringArrayEquals(String message, String[] expected, String[] result) {
        String expectedString = Arrays.toString(expected);
        String expectedString = Arrays.toString(expected);
        String resultString = Arrays.toString(result);
        String resultString = Arrays.toString(result);