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

Commit 00e5bef5 authored by Julia Reynolds's avatar Julia Reynolds
Browse files

Move timing of conversation channel creation

Before: onBind
Now: when the user has an actual change to make

Test: NotificationConversationInfoTest
Bug: 395857098
Fixes: 405952296
Flag: EXEMPT bug fix
Change-Id: Ib99bd5e5f37836d4b6f73a45ff944645a212a5f1
parent 9557e44e
Loading
Loading
Loading
Loading
+14 −10
Original line number Diff line number Diff line
@@ -26,6 +26,8 @@ import android.content.Context;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.UserHandle;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.text.TextUtils;
import android.util.Slog;

@@ -41,7 +43,8 @@ public class NotificationChannelHelper {
    public static NotificationChannel createConversationChannelIfNeeded(
            Context context,
            INotificationManager notificationManager,
            NotificationEntry entry,
            NotificationListenerService.Ranking ranking,
            StatusBarNotification sbn,
            NotificationChannel channel) {
        if (notificationClassification() && SYSTEM_RESERVED_IDS.contains(channel.getId())) {
            return channel;
@@ -49,18 +52,18 @@ public class NotificationChannelHelper {
        if (!TextUtils.isEmpty(channel.getConversationId())) {
            return channel;
        }
        final String conversationId = entry.getSbn().getShortcutId();
        final String pkg = entry.getSbn().getPackageName();
        final int appUid = entry.getSbn().getUid();
        final String conversationId =sbn.getShortcutId();
        final String pkg = sbn.getPackageName();
        final int appUid = sbn.getUid();
        if (TextUtils.isEmpty(conversationId) || TextUtils.isEmpty(pkg)
            || entry.getRanking().getConversationShortcutInfo() == null) {
            || ranking.getConversationShortcutInfo() == null) {
            return channel;
        }

        // If this channel is not already a customized conversation channel, create
        // a custom channel
        try {
            channel.setName(getName(entry));
            channel.setName(getName(ranking, sbn));
            notificationManager.createConversationNotificationChannelForPackage(
                    pkg, appUid, channel,
                    conversationId);
@@ -73,11 +76,12 @@ public class NotificationChannelHelper {
        return channel;
    }

    private static CharSequence getName(NotificationEntry entry) {
        if (entry.getRanking().getConversationShortcutInfo().getLabel() != null) {
            return entry.getRanking().getConversationShortcutInfo().getLabel().toString();
    public static CharSequence getName(NotificationListenerService.Ranking ranking,
            StatusBarNotification sbn) {
        if (ranking.getConversationShortcutInfo().getLabel() != null) {
            return ranking.getConversationShortcutInfo().getLabel().toString();
        }
        Bundle extras = entry.getSbn().getNotification().extras;
        Bundle extras = sbn.getNotification().extras;
        CharSequence nameString = extras.getCharSequence(Notification.EXTRA_CONVERSATION_TITLE);
        if (TextUtils.isEmpty(nameString)) {
            nameString = extras.getCharSequence(Notification.EXTRA_TITLE);
+9 −19
Original line number Diff line number Diff line
@@ -250,9 +250,6 @@ public class NotificationConversationInfo extends LinearLayout implements
            throw new IllegalArgumentException("Does not have required information");
        }

        mNotificationChannel = NotificationChannelHelper.createConversationChannelIfNeeded(
                getContext(), mINotificationManager, entry, mNotificationChannel);

        try {
            mAppBubble = mINotificationManager.getBubblePreferenceForPackage(mPackageName, mAppUid);
        } catch (RemoteException e) {
@@ -276,19 +273,6 @@ public class NotificationConversationInfo extends LinearLayout implements
    }

    private void bindActions() {

        // TODO: b/152050825
        /*
        Button home = findViewById(R.id.home);
        home.setOnClickListener(mOnHomeClick);
        home.setVisibility(mShortcutInfo != null
                && mShortcutManager.isRequestPinShortcutSupported()
                ? VISIBLE : GONE);

        Button snooze = findViewById(R.id.snooze);
        snooze.setOnClickListener(mOnSnoozeClick);
        */

        TextView defaultSummaryTextView = findViewById(R.id.default_summary);
        if (mAppBubble == BUBBLE_PREFERENCE_ALL
                && BubblesManager.areBubblesEnabled(mContext, mSbn.getUser())) {
@@ -351,11 +335,9 @@ public class NotificationConversationInfo extends LinearLayout implements

    private void bindConversationDetails() {
        final TextView channelName = findViewById(R.id.parent_channel_name);
        channelName.setText(mNotificationChannel.getName());
        channelName.setText(NotificationChannelHelper.getName(mRanking, mSbn));

        bindGroup();
        // TODO: bring back when channel name does not include name
        // bindName();
        bindPackage();
        bindIcon(mNotificationChannel.isImportantConversation());

@@ -670,6 +652,14 @@ public class NotificationConversationInfo extends LinearLayout implements
        @Override
        public void run() {
            try {
                if (!mChannelToUpdate.isConversation()) {
                    // first, create the channel just for this conversation
                    mChannelToUpdate =
                            NotificationChannelHelper.createConversationChannelIfNeeded(
                                    getContext(), mINotificationManager, mRanking, mSbn,
                                    mChannelToUpdate);
                }

                switch (mAction) {
                    case ACTION_FAVORITE:
                        mChannelToUpdate.setImportantConversation(true);
+1 −1
Original line number Diff line number Diff line
@@ -669,7 +669,7 @@ public class BubblesManager {

        // Change the settings
        channel = NotificationChannelHelper.createConversationChannelIfNeeded(mContext,
                mNotificationManager, entry, channel);
                mNotificationManager, entry.getRanking(), entry.getSbn(), channel);
        channel.setAllowBubbles(shouldBubble);
        try {
            int currentPref = mNotificationManager.getBubblePreferenceForPackage(appPkg, appUid);
+75 −36
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;

import static org.junit.Assert.assertNotEquals;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.anyString;
@@ -86,6 +87,7 @@ import androidx.test.filters.SmallTest;
import com.android.internal.logging.MetricsLogger;
import com.android.settingslib.notification.ConversationIconFactory;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.kosmos.KosmosJavaAdapter;
import com.android.systemui.people.widget.PeopleSpaceWidgetManager;
import com.android.systemui.res.R;
import com.android.systemui.shade.ShadeController;
@@ -125,6 +127,8 @@ import java.util.concurrent.CountDownLatch;
@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
public class NotificationConversationInfoTest extends SysuiTestCase {

    private final KosmosJavaAdapter mKosmos = new KosmosJavaAdapter(this);
    private static final String TEST_PACKAGE_NAME = "test_package";
    private static final String TEST_SYSTEM_PACKAGE_NAME = PRINT_SPOOLER_PACKAGE_NAME;
    private static final int TEST_UID = 1;
@@ -139,8 +143,6 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
    private StatusBarNotification mSbn;
    private NotificationEntry mEntry;
    private EntryAdapter mEntryAdapter;
    private StatusBarNotification mBubbleSbn;
    private NotificationEntry mBubbleEntry;
    @Mock
    private ShortcutInfo mShortcutInfo;
    @Mock
@@ -173,8 +175,6 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
    @Mock
    private ConversationIconFactory mIconFactory;
    @Mock
    private Notification.BubbleMetadata mBubbleMetadata;
    @Mock
    private View.OnClickListener mCloseListener;
    private Handler mTestHandler;
    @Rule
@@ -236,8 +236,13 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
        mNotificationChannel = new NotificationChannel(
                TEST_CHANNEL, TEST_CHANNEL_NAME, IMPORTANCE_LOW);

        PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, 0,
                new Intent(mContext, BubblesTestActivity.class),
                PendingIntent.FLAG_MUTABLE);
        Notification notification = new Notification.Builder(mContext, mNotificationChannel.getId())
                .setShortcutId(CONVERSATION_ID)
                .setBubbleMetadata(new Notification.BubbleMetadata.Builder(bubbleIntent,
                        Icon.createWithResource(mContext, R.drawable.android)).build())
                .setStyle(new Notification.MessagingStyle(new Person.Builder().setName("m").build())
                        .addMessage(new Notification.MessagingStyle.Message(
                                "hello!", 1000, new Person.Builder().setName("other").build())))
@@ -250,28 +255,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
                    rankingBuilder.setChannel(mNotificationChannel);
                })
                .build();
        mEntryAdapter = new EntryAdapterFactoryImpl(
                mock(NotificationActivityStarter.class),
                mock(MetricsLogger.class),
                mock(PeopleNotificationIdentifier.class),
                mock(NotificationIconStyleProvider.class),
                mock(VisualStabilityCoordinator.class),
                mock(NotificationActionClickManager.class),
                mock(HighPriorityProvider.class),
                mock(HeadsUpManager.class)
        ).create(mEntry);

        PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, 0,
                new Intent(mContext, BubblesTestActivity.class),
                PendingIntent.FLAG_MUTABLE);
        mBubbleSbn = new SbnBuilder(mSbn).setBubbleMetadata(
                        new Notification.BubbleMetadata.Builder(bubbleIntent,
                                Icon.createWithResource(mContext, R.drawable.android)).build())
                .build();
        mBubbleEntry = new NotificationEntryBuilder()
                .setSbn(mBubbleSbn)
                .setShortcutInfo(mShortcutInfo)
                .build();
        mEntryAdapter = mKosmos.getEntryAdapterFactory().create(mEntry);

        mConversationChannel = new NotificationChannel(
                TEST_CHANNEL + " : " + CONVERSATION_ID, TEST_CHANNEL_NAME, IMPORTANCE_LOW);
@@ -292,6 +276,35 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
        mTestableLooper.processAllMessages();
    }

    /**
     * Binds the view with a channel that's already a conversation channel
     */
    private void doConversationBind() {
        RankingBuilder rb = new RankingBuilder(mEntry.getRanking());
        rb.setChannel(mConversationChannel);
        mEntry.setRanking(rb.build());
        mNotificationInfo.bindNotification(
                mShortcutManager,
                mMockPackageManager,
                mUserManager,
                mPeopleSpaceWidgetManager,
                mMockINotificationManager,
                mOnUserInteractionCallback,
                TEST_PACKAGE_NAME,
                mEntry,
                mEntryAdapter,
                mEntry.getRanking(),
                mSbn,
                null,
                null,
                mIconFactory,
                mContext,
                true,
                mTestHandler,
                mTestHandler, null, Optional.of(mBubblesManager),
                mShadeController, true, mCloseListener);
    }

    private void doStandardBind() {
        mNotificationInfo.bindNotification(
                mShortcutManager,
@@ -489,7 +502,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
                mEntry.getRanking(),
                mSbn,
                (View v, NotificationChannel c, int appUid) -> {
                    assertEquals(mConversationChannel, c);
                    assertEquals(mNotificationChannel, c);
                    latch.countDown();
                },
                null,
@@ -559,7 +572,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
        mConversationChannel.setImportance(IMPORTANCE_HIGH);
        mConversationChannel.setImportantConversation(false);
        mConversationChannel.setAllowBubbles(true);
        doStandardBind();
        doConversationBind();
        View view = mNotificationInfo.findViewById(R.id.default_behavior);
        assertThat(view.isSelected()).isTrue();
        assertThat(((TextView) view.findViewById(R.id.default_summary)).getText()).isEqualTo(
@@ -574,7 +587,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
        mConversationChannel.setImportance(IMPORTANCE_HIGH);
        mConversationChannel.setImportantConversation(false);
        mConversationChannel.setAllowBubbles(true);
        doStandardBind();
        doConversationBind();
        View view = mNotificationInfo.findViewById(R.id.default_behavior);
        assertThat(view.isSelected()).isTrue();
        assertThat(((TextView) view.findViewById(R.id.default_summary)).getText()).isEqualTo(
@@ -666,7 +679,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
        mConversationChannel.setImportance(IMPORTANCE_HIGH);
        mConversationChannel.setImportantConversation(false);
        mConversationChannel.setAllowBubbles(true);
        doStandardBind();
        doConversationBind();
        assertThat(((TextView) mNotificationInfo.findViewById(R.id.priority_summary)).getText())
                .isEqualTo(mContext.getString(
                        R.string.notification_channel_summary_priority_all));
@@ -678,7 +691,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
        mConversationChannel.setImportance(IMPORTANCE_LOW);
        mConversationChannel.setImportantConversation(false);

        doStandardBind();
        doConversationBind();

        View fave = mNotificationInfo.findViewById(R.id.priority);
        fave.performClick();
@@ -756,12 +769,35 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
    }

    @Test
    public void testFavorite_andSave() throws Exception {
    public void testFavorite_andSave_createConversation() throws Exception {
        doStandardBind();

        View fave = mNotificationInfo.findViewById(R.id.priority);
        fave.performClick();
        mNotificationInfo.findViewById(R.id.done).performClick();
        mTestableLooper.processAllMessages();

        ArgumentCaptor<NotificationChannel> captor =
                ArgumentCaptor.forClass(NotificationChannel.class);
        verify(mMockINotificationManager, times(1))
                .createConversationNotificationChannelForPackage(
                        anyString(), anyInt(), any(), anyString());
        verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
                anyString(), anyInt(), captor.capture());
        assertTrue(captor.getValue().isImportantConversation());
        assertTrue(captor.getValue().canBubble());
        assertEquals(IMPORTANCE_DEFAULT, captor.getValue().getImportance());
        assertFalse(mNotificationInfo.shouldBeSavedOnClose());
        assertNotEquals(captor.getValue().getId(), mNotificationChannel.getId());
    }

    @Test
    public void testFavorite_andSave_alreadyConversation() throws Exception {
        mConversationChannel.setAllowBubbles(false);
        mConversationChannel.setImportance(IMPORTANCE_LOW);
        mConversationChannel.setImportantConversation(false);

        doStandardBind();
        doConversationBind();

        View fave = mNotificationInfo.findViewById(R.id.priority);
        fave.performClick();
@@ -770,6 +806,9 @@ public class NotificationConversationInfoTest extends SysuiTestCase {

        ArgumentCaptor<NotificationChannel> captor =
                ArgumentCaptor.forClass(NotificationChannel.class);
        verify(mMockINotificationManager, never())
                .createConversationNotificationChannelForPackage(
                        anyString(), anyInt(), any(), anyString());
        verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
                anyString(), anyInt(), captor.capture());
        assertTrue(captor.getValue().isImportantConversation());
@@ -827,7 +866,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
        mConversationChannel.setImportantConversation(false);

        // WHEN we indicate no selected action
        doStandardBind();
        doConversationBind();

        // THEN the selected action is -1, so the selected option is "Default" priority
        assertEquals(mNotificationInfo.getSelectedAction(), -1);
@@ -951,10 +990,10 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
    }

    @Test
    public void testBindNotification_createsNewChannel() throws Exception {
    public void testBindNotification_neverCreatesNewChannel() throws Exception {
        doStandardBind();

        verify(mMockINotificationManager, times(1)).createConversationNotificationChannelForPackage(
        verify(mMockINotificationManager, never()).createConversationNotificationChannelForPackage(
                anyString(), anyInt(), any(), eq(CONVERSATION_ID));
    }