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

Commit 8e52d9ff authored by Julia Reynolds's avatar Julia Reynolds Committed by Android (Google) Code Review
Browse files

Merge "Move timing of conversation channel creation" into main

parents f7ec336b 00e5bef5
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));
    }