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

Commit bb6ee756 authored by Alexander Roederer's avatar Alexander Roederer
Browse files

Moves test utils from NLSTest to RankingTest

Moves some test utilities for checking NotificationRanking equality, and
copies some utilities for generating NotificationRankings, from
NotificationListenerServiceTest to NotificationRankingUpdateTest.

Also moves some tests focused on Rankings to NotificationRankingUpdateTest.
These will be deduplicated in the next cl.

Test: Modification of tests only; ran atest on both
Bug: 249848655
Change-Id: I3872396da815368750b5784bc28b6c972d90190c
parent 43221a63
Loading
Loading
Loading
Loading
+434 −0
Original line number Diff line number Diff line
@@ -16,6 +16,10 @@

package android.service.notification;

import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE;
import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL;
import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_POSITIVE;

import static com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags.RANKING_UPDATE_ASHMEM;

import static junit.framework.Assert.assertEquals;
@@ -24,20 +28,36 @@ import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertNotEquals;
import static org.mockito.Mockito.spy;

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ShortcutInfo;
import android.os.Parcel;
import android.testing.TestableContext;

import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;

import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags;

import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;

import java.util.ArrayList;
import java.util.List;

@SmallTest
@RunWith(Parameterized.class)
public class NotificationRankingUpdateTest {
@@ -56,6 +76,340 @@ public class NotificationRankingUpdateTest {
    @Parameterized.Parameter
    public boolean mRankingUpdateAshmem;

    @Rule
    public TestableContext mContext =
            spy(new TestableContext(InstrumentationRegistry.getContext(), null));

    protected TestableContext getContext() {
        return mContext;
    }

    public static String[] mKeys = new String[] { "key", "key1", "key2", "key3", "key4"};

    /**
     * Creates a NotificationRankingUpdate with prepopulated Ranking entries
     * @param context A testable context, used for PendingIntent creation
     * @return The NotificationRankingUpdate to be used as test data
     */
    public static NotificationRankingUpdate generateUpdate(TestableContext context) {
        NotificationListenerService.Ranking[] rankings =
                new NotificationListenerService.Ranking[mKeys.length];
        for (int i = 0; i < mKeys.length; i++) {
            final String key = mKeys[i];
            NotificationListenerService.Ranking ranking = new NotificationListenerService.Ranking();
            ranking.populate(
                    key,
                    i,
                    !isIntercepted(i),
                    getVisibilityOverride(i),
                    getSuppressedVisualEffects(i),
                    getImportance(i),
                    getExplanation(key),
                    getOverrideGroupKey(key),
                    getChannel(key, i),
                    getPeople(key, i),
                    getSnoozeCriteria(key, i),
                    getShowBadge(i),
                    getUserSentiment(i),
                    getHidden(i),
                    lastAudiblyAlerted(i),
                    getNoisy(i),
                    getSmartActions(key, i, context),
                    getSmartReplies(key, i),
                    canBubble(i),
                    isTextChanged(i),
                    isConversation(i),
                    getShortcutInfo(i),
                    getRankingAdjustment(i),
                    isBubble(i),
                    getProposedImportance(i),
                    hasSensitiveContent(i)
            );
            rankings[i] = ranking;
        }
        return new NotificationRankingUpdate(rankings);
    }

    /**
     * Produces a visibility override value based on the provided index.
     */
    public static int getVisibilityOverride(int index) {
        return index * 9;
    }

    /**
     * Produces a group key based on the provided key.
     */
    public static String getOverrideGroupKey(String key) {
        return key + key;
    }

    /**
     * Produces a boolean that can be used to represent isIntercepted, based on the provided index.
     */
    public static boolean isIntercepted(int index) {
        return index % 2 == 0;
    }

    /**
     * Produces a suppressed visual effects value based on the provided index
     */
    public static int getSuppressedVisualEffects(int index) {
        return index * 2;
    }

    /**
     * Produces an importance value, based on the provided index
     */
    public static int getImportance(int index) {
        return index;
    }

    /**
     * Produces an explanation value, based on the provided key
     */
    public static String getExplanation(String key) {
        return key + "explain";
    }

    /**
     * Produces a notification channel, based on the provided key and index
     */
    public static NotificationChannel getChannel(String key, int index) {
        return new NotificationChannel(key, key, getImportance(index));
    }

    /**
     * Produces a boolean that can be used to represent showBadge, based on the provided index
     */
    public static boolean getShowBadge(int index) {
        return index % 3 == 0;
    }

    /**
     * Produces a user sentiment value, based on the provided index
     */
    public static int getUserSentiment(int index) {
        switch(index % 3) {
            case 0:
                return USER_SENTIMENT_NEGATIVE;
            case 1:
                return USER_SENTIMENT_NEUTRAL;
            case 2:
                return USER_SENTIMENT_POSITIVE;
        }
        return USER_SENTIMENT_NEUTRAL;
    }

    /**
     * Produces a boolean that can be used to represent "hidden," based on the provided index.
     */
    public static boolean getHidden(int index) {
        return index % 2 == 0;
    }

    /**
     * Produces a long to represent lastAudiblyAlerted based on the provided index.
     */
    public static long lastAudiblyAlerted(int index) {
        return index * 2000L;
    }

    /**
     * Produces a boolean that can be used to represent "noisy," based on the provided index.
     */
    public static boolean getNoisy(int index) {
        return index < 1;
    }

    /**
     * Produces strings that can be used to represent people, based on the provided key and index.
     */
    public static ArrayList<String> getPeople(String key, int index) {
        ArrayList<String> people = new ArrayList<>();
        for (int i = 0; i < index; i++) {
            people.add(i + key);
        }
        return people;
    }

    /**
     * Produces a number of snoozeCriteria, based on the provided key and index.
     */
    public static ArrayList<SnoozeCriterion> getSnoozeCriteria(String key, int index) {
        ArrayList<SnoozeCriterion> snooze = new ArrayList<>();
        for (int i = 0; i < index; i++) {
            snooze.add(new SnoozeCriterion(key + i, getExplanation(key), key));
        }
        return snooze;
    }

    /**
     * Produces a list of Actions which can be used to represent smartActions.
     * These actions are built from pending intents with intent titles based on the provided
     * key, and ids based on the provided index.
     */
    public static ArrayList<Notification.Action> getSmartActions(String key,
                                                                 int index,
                                                                 TestableContext context) {
        ArrayList<Notification.Action> actions = new ArrayList<>();
        for (int i = 0; i < index; i++) {
            PendingIntent intent = PendingIntent.getBroadcast(
                    context,
                    index /*requestCode*/,
                    new Intent("ACTION_" + key),
                    PendingIntent.FLAG_IMMUTABLE /*flags*/);
            actions.add(new Notification.Action.Builder(null /*icon*/, key, intent).build());
        }
        return actions;
    }

    /**
     * Produces index number of "smart replies," all based on the provided key and index
     */
    public static ArrayList<CharSequence> getSmartReplies(String key, int index) {
        ArrayList<CharSequence> choices = new ArrayList<>();
        for (int i = 0; i < index; i++) {
            choices.add("choice_" + key + "_" + i);
        }
        return choices;
    }

    /**
     * Produces a boolean that can be  used to represent canBubble, based on the provided index
     */
    public static boolean canBubble(int index) {
        return index % 4 == 0;
    }

    /**
     * Produces a boolean that can be used to represent isTextChanged, based on the provided index.
     */
    public static boolean isTextChanged(int index) {
        return index % 4 == 0;
    }

    /**
     * Produces a boolean that can be used to represent isConversation, based on the provided index.
     */
    public static boolean isConversation(int index) {
        return index % 4 == 0;
    }

    /**
     * Produces a ShortcutInfo value based on the provided index.
     */
    public static ShortcutInfo getShortcutInfo(int index) {
        ShortcutInfo si = new ShortcutInfo(
                index, String.valueOf(index), "packageName", new ComponentName("1", "1"), null,
                "title", 0, "titleResName", "text", 0, "textResName",
                "disabledMessage", 0, "disabledMessageResName",
                null, null, 0, null, 0, 0,
                0, "iconResName", "bitmapPath", null, 0,
                null, null, null, null);
        return si;
    }

    /**
     * Produces a rankingAdjustment value, based on the provided index.
     */
    public static int getRankingAdjustment(int index) {
        return index % 3 - 1;
    }

    /**
     * Produces a proposedImportance, based on the provided index.
     */
    public static int getProposedImportance(int index) {
        return index % 5 - 1;
    }

    /**
     * Produces a boolean that can be used to represent hasSensitiveContent, based on the provided
     * index.
     */
    public static boolean hasSensitiveContent(int index) {
        return index % 3 == 0;
    }

    /**
     * Produces a boolean that can be used to represent isBubble, based on the provided index.
     */
    public static boolean isBubble(int index) {
        return index % 4 == 0;
    }

    /**
     * Checks that each of the pairs of actions in the two provided lists has identical titles,
     * and that the lists have the same number of elements.
     */
    public void assertActionsEqual(
            List<Notification.Action> expecteds, List<Notification.Action> actuals) {
        Assert.assertEquals(expecteds.size(), actuals.size());
        for (int i = 0; i < expecteds.size(); i++) {
            Notification.Action expected = expecteds.get(i);
            Notification.Action actual = actuals.get(i);
            Assert.assertEquals(expected.title.toString(), actual.title.toString());
        }
    }

    /**
     * Checks that all subelements of the provided NotificationRankingUpdates are equal.
     */
    public void detailedAssertEquals(NotificationRankingUpdate a, NotificationRankingUpdate b) {
        detailedAssertEquals(a.getRankingMap(), b.getRankingMap());
    }

    /**
     * Checks that all subelements of the provided Ranking objects are equal.
     */
    public void detailedAssertEquals(String comment, NotificationListenerService.Ranking a,
                                     NotificationListenerService.Ranking b) {
        Assert.assertEquals(comment, a.getKey(), b.getKey());
        Assert.assertEquals(comment, a.getRank(), b.getRank());
        Assert.assertEquals(comment, a.matchesInterruptionFilter(), b.matchesInterruptionFilter());
        Assert.assertEquals(comment, a.getLockscreenVisibilityOverride(),
                b.getLockscreenVisibilityOverride());
        Assert.assertEquals(comment, a.getSuppressedVisualEffects(),
                b.getSuppressedVisualEffects());
        Assert.assertEquals(comment, a.getImportance(), b.getImportance());
        Assert.assertEquals(comment, a.getImportanceExplanation(), b.getImportanceExplanation());
        Assert.assertEquals(comment, a.getOverrideGroupKey(), b.getOverrideGroupKey());
        Assert.assertEquals(comment, a.getChannel().toString(), b.getChannel().toString());
        Assert.assertEquals(comment, a.getAdditionalPeople(), b.getAdditionalPeople());
        Assert.assertEquals(comment, a.getSnoozeCriteria(), b.getSnoozeCriteria());
        Assert.assertEquals(comment, a.canShowBadge(), b.canShowBadge());
        Assert.assertEquals(comment, a.getUserSentiment(), b.getUserSentiment());
        Assert.assertEquals(comment, a.isSuspended(), b.isSuspended());
        Assert.assertEquals(comment, a.getLastAudiblyAlertedMillis(),
                b.getLastAudiblyAlertedMillis());
        Assert.assertEquals(comment, a.isNoisy(), b.isNoisy());
        Assert.assertEquals(comment, a.getSmartReplies(), b.getSmartReplies());
        Assert.assertEquals(comment, a.canBubble(), b.canBubble());
        Assert.assertEquals(comment, a.isConversation(), b.isConversation());
        Assert.assertEquals(comment, a.getConversationShortcutInfo().getId(),
                b.getConversationShortcutInfo().getId());
        assertActionsEqual(a.getSmartActions(), b.getSmartActions());
        Assert.assertEquals(a.getProposedImportance(), b.getProposedImportance());
        Assert.assertEquals(a.hasSensitiveContent(), b.hasSensitiveContent());
    }

    /**
     * Checks that the two RankingMaps have identical keys, and that each Ranking object for
     * each of those keys is identical.
     */
    public void detailedAssertEquals(NotificationListenerService.RankingMap a,
                                     NotificationListenerService.RankingMap b) {
        NotificationListenerService.Ranking arank = new NotificationListenerService.Ranking();
        NotificationListenerService.Ranking brank = new NotificationListenerService.Ranking();
        assertArrayEquals(a.getOrderedKeys(), b.getOrderedKeys());
        for (String key : a.getOrderedKeys()) {
            a.getRanking(key, arank);
            b.getRanking(key, brank);
            detailedAssertEquals("ranking for key <" + key + ">", arank, brank);
        }
    }

    @Before
    public void setUp() {
        mNotificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, "test channel",
@@ -196,4 +550,84 @@ public class NotificationRankingUpdateTest {
                new NotificationListenerService.Ranking[]{ranking2});
        assertTrue(rankingUpdate.equals(rankingUpdate2));
    }

    // Tests parceling of NotificationRankingUpdate, and by extension, RankingMap and Ranking.
    @Test
    public void testRankingUpdate_parcel_legacy() {
        NotificationRankingUpdate nru = generateUpdate(getContext());
        Parcel parcel = Parcel.obtain();
        nru.writeToParcel(parcel, 0);
        parcel.setDataPosition(0);
        NotificationRankingUpdate nru1 = NotificationRankingUpdate.CREATOR.createFromParcel(parcel);
        detailedAssertEquals(nru, nru1);
    }

    // Tests parceling of RankingMap and RankingMap.equals
    @Test
    public void testRankingMap_parcel_legacy() {
        NotificationListenerService.RankingMap rmap = generateUpdate(getContext()).getRankingMap();
        Parcel parcel = Parcel.obtain();
        rmap.writeToParcel(parcel, 0);
        parcel.setDataPosition(0);
        NotificationListenerService.RankingMap rmap1 =
                NotificationListenerService.RankingMap.CREATOR.createFromParcel(parcel);

        detailedAssertEquals(rmap, rmap1);
        Assert.assertEquals(rmap, rmap1);
    }

    // Tests parceling of Ranking and Ranking.equals
    @Test
    public void testRanking_parcel_legacy() {
        NotificationListenerService.Ranking ranking =
                generateUpdate(getContext()).getRankingMap().getRawRankingObject(mKeys[0]);
        Parcel parcel = Parcel.obtain();
        ranking.writeToParcel(parcel, 0);
        parcel.setDataPosition(0);
        NotificationListenerService.Ranking ranking1 =
                new NotificationListenerService.Ranking(parcel);
        detailedAssertEquals("rankings differ: ", ranking, ranking1);
        Assert.assertEquals(ranking, ranking1);
    }

    // Tests NotificationRankingUpdate.equals(), and by extension, RankingMap and Ranking.
    @Test
    public void testRankingUpdate_equals_legacy() {
        NotificationRankingUpdate nru = generateUpdate(getContext());
        NotificationRankingUpdate nru2 = generateUpdate(getContext());
        detailedAssertEquals(nru, nru2);
        Assert.assertEquals(nru, nru2);
        NotificationListenerService.Ranking tweak =
                nru2.getRankingMap().getRawRankingObject(mKeys[0]);
        tweak.populate(
                tweak.getKey(),
                tweak.getRank(),
                !tweak.matchesInterruptionFilter(), // note the inversion here!
                tweak.getLockscreenVisibilityOverride(),
                tweak.getSuppressedVisualEffects(),
                tweak.getImportance(),
                tweak.getImportanceExplanation(),
                tweak.getOverrideGroupKey(),
                tweak.getChannel(),
                (ArrayList) tweak.getAdditionalPeople(),
                (ArrayList) tweak.getSnoozeCriteria(),
                tweak.canShowBadge(),
                tweak.getUserSentiment(),
                tweak.isSuspended(),
                tweak.getLastAudiblyAlertedMillis(),
                tweak.isNoisy(),
                (ArrayList) tweak.getSmartActions(),
                (ArrayList) tweak.getSmartReplies(),
                tweak.canBubble(),
                tweak.isTextChanged(),
                tweak.isConversation(),
                tweak.getConversationShortcutInfo(),
                tweak.getRankingAdjustment(),
                tweak.isBubble(),
                tweak.getProposedImportance(),
                tweak.hasSensitiveContent()
        );
        assertNotEquals(nru, nru2);
    }

}
+0 −122
Original line number Diff line number Diff line
@@ -23,9 +23,7 @@ import static android.service.notification.NotificationListenerService.Ranking.U

import static com.google.common.truth.Truth.assertThat;

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.mockito.ArgumentMatchers.any;
@@ -49,12 +47,10 @@ import android.graphics.drawable.Icon;
import android.os.Binder;
import android.os.Build;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
import android.os.UserHandle;
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationListenerService.Ranking;
import android.service.notification.NotificationListenerService.RankingMap;
import android.service.notification.NotificationRankingUpdate;
import android.service.notification.SnoozeCriterion;
import android.service.notification.StatusBarNotification;
@@ -158,81 +154,6 @@ public class NotificationListenerServiceTest extends UiServiceTestCase {
        }
    }

    // Tests parceling of NotificationRankingUpdate, and by extension, RankingMap and Ranking.
    @Test
    public void testRankingUpdate_parcel() {
        NotificationRankingUpdate nru = generateUpdate();
        Parcel parcel = Parcel.obtain();
        nru.writeToParcel(parcel, 0);
        parcel.setDataPosition(0);
        NotificationRankingUpdate nru1 = NotificationRankingUpdate.CREATOR.createFromParcel(parcel);
        assertEquals(nru, nru1);
    }

    // Tests parceling of RankingMap and RankingMap.equals
    @Test
    public void testRankingMap_parcel() {
        RankingMap rmap = generateUpdate().getRankingMap();
        Parcel parcel = Parcel.obtain();
        rmap.writeToParcel(parcel, 0);
        parcel.setDataPosition(0);
        RankingMap rmap1 = RankingMap.CREATOR.createFromParcel(parcel);

        detailedAssertEquals(rmap, rmap1);
        assertEquals(rmap, rmap1);
    }

    // Tests parceling of Ranking and Ranking.equals
    @Test
    public void testRanking_parcel() {
        Ranking ranking = generateUpdate().getRankingMap().getRawRankingObject(mKeys[0]);
        Parcel parcel = Parcel.obtain();
        ranking.writeToParcel(parcel, 0);
        parcel.setDataPosition(0);
        Ranking ranking1 = new Ranking(parcel);
        detailedAssertEquals("rankings differ: ", ranking, ranking1);
        assertEquals(ranking, ranking1);
    }

    // Tests NotificationRankingUpdate.equals(), and by extension, RankingMap and Ranking.
    @Test
    public void testRankingUpdate_equals() {
        NotificationRankingUpdate nru = generateUpdate();
        NotificationRankingUpdate nru2 = generateUpdate();
        detailedAssertEquals(nru, nru2);
        assertEquals(nru, nru2);
        Ranking tweak = nru2.getRankingMap().getRawRankingObject(mKeys[0]);
        tweak.populate(
                tweak.getKey(),
                tweak.getRank(),
                !tweak.matchesInterruptionFilter(), // note the inversion here!
                tweak.getLockscreenVisibilityOverride(),
                tweak.getSuppressedVisualEffects(),
                tweak.getImportance(),
                tweak.getImportanceExplanation(),
                tweak.getOverrideGroupKey(),
                tweak.getChannel(),
                (ArrayList) tweak.getAdditionalPeople(),
                (ArrayList) tweak.getSnoozeCriteria(),
                tweak.canShowBadge(),
                tweak.getUserSentiment(),
                tweak.isSuspended(),
                tweak.getLastAudiblyAlertedMillis(),
                tweak.isNoisy(),
                (ArrayList) tweak.getSmartActions(),
                (ArrayList) tweak.getSmartReplies(),
                tweak.canBubble(),
                tweak.isTextChanged(),
                tweak.isConversation(),
                tweak.getConversationShortcutInfo(),
                tweak.getRankingAdjustment(),
                tweak.isBubble(),
                tweak.getProposedImportance(),
                tweak.hasSensitiveContent()
        );
        assertNotEquals(nru, nru2);
    }

    @Test
    public void testLegacyIcons_preM() {
        TestListenerService service = new TestListenerService();
@@ -275,7 +196,6 @@ public class NotificationListenerServiceTest extends UiServiceTestCase {
        assertNull(n.largeIcon);
    }


    // Test data

    private String[] mKeys = new String[] { "key", "key1", "key2", "key3", "key4"};
@@ -461,48 +381,6 @@ public class NotificationListenerServiceTest extends UiServiceTestCase {
        }
    }

    private void detailedAssertEquals(NotificationRankingUpdate a, NotificationRankingUpdate b) {
        detailedAssertEquals(a.getRankingMap(), b.getRankingMap());
    }

    private void detailedAssertEquals(String comment, Ranking a, Ranking b) {
        assertEquals(comment, a.getKey(), b.getKey());
        assertEquals(comment, a.getRank(), b.getRank());
        assertEquals(comment, a.matchesInterruptionFilter(), b.matchesInterruptionFilter());
        assertEquals(comment, a.getLockscreenVisibilityOverride(), b.getLockscreenVisibilityOverride());
        assertEquals(comment, a.getSuppressedVisualEffects(), b.getSuppressedVisualEffects());
        assertEquals(comment, a.getImportance(), b.getImportance());
        assertEquals(comment, a.getImportanceExplanation(), b.getImportanceExplanation());
        assertEquals(comment, a.getOverrideGroupKey(), b.getOverrideGroupKey());
        assertEquals(comment, a.getChannel(), b.getChannel());
        assertEquals(comment, a.getAdditionalPeople(), b.getAdditionalPeople());
        assertEquals(comment, a.getSnoozeCriteria(), b.getSnoozeCriteria());
        assertEquals(comment, a.canShowBadge(), b.canShowBadge());
        assertEquals(comment, a.getUserSentiment(), b.getUserSentiment());
        assertEquals(comment, a.isSuspended(), b.isSuspended());
        assertEquals(comment, a.getLastAudiblyAlertedMillis(), b.getLastAudiblyAlertedMillis());
        assertEquals(comment, a.isNoisy(), b.isNoisy());
        assertEquals(comment, a.getSmartReplies(), b.getSmartReplies());
        assertEquals(comment, a.canBubble(), b.canBubble());
        assertEquals(comment, a.isConversation(), b.isConversation());
        assertEquals(comment, a.getConversationShortcutInfo().getId(),
                b.getConversationShortcutInfo().getId());
        assertActionsEqual(a.getSmartActions(), b.getSmartActions());
        assertEquals(a.getProposedImportance(), b.getProposedImportance());
        assertEquals(a.hasSensitiveContent(), b.hasSensitiveContent());
    }

    private void detailedAssertEquals(RankingMap a, RankingMap b) {
        Ranking arank = new Ranking();
        Ranking brank = new Ranking();
        assertArrayEquals(a.getOrderedKeys(), b.getOrderedKeys());
        for (String key : a.getOrderedKeys()) {
            a.getRanking(key, arank);
            b.getRanking(key, brank);
            detailedAssertEquals("ranking for key <" + key + ">", arank, brank);
        }
    }

    public static class TestListenerService extends NotificationListenerService {
        private final IBinder binder = new LocalBinder();
        public int targetSdk = 0;