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

Commit fe589526 authored by Steve Elliott's avatar Steve Elliott Committed by Automerger Merge Worker
Browse files

Merge "Uprank colorized FSNs over Conversations" into rvc-dev am: 4ba34ed6

Change-Id: I50d98eda214e346e0899357fc6fe02198c08c72d
parents 5744efec 4ba34ed6
Loading
Loading
Loading
Loading
+7 −4
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.provider.DeviceConfig
import com.android.internal.annotations.VisibleForTesting
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags.NOTIFICATIONS_USE_PEOPLE_FILTERING
import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING
import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_FOREGROUND_SERVICE
import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_HEADS_UP
import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_MEDIA_CONTROLS
import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_PEOPLE
@@ -52,12 +53,14 @@ class NotificationSectionsFeatureManager @Inject constructor(
    fun getNotificationBuckets(): IntArray {
        return when {
            isFilteringEnabled() && isMediaControlsEnabled() ->
                intArrayOf(BUCKET_HEADS_UP, BUCKET_MEDIA_CONTROLS, BUCKET_PEOPLE, BUCKET_ALERTING,
                    BUCKET_SILENT)
                intArrayOf(BUCKET_HEADS_UP, BUCKET_FOREGROUND_SERVICE, BUCKET_MEDIA_CONTROLS,
                        BUCKET_PEOPLE, BUCKET_ALERTING, BUCKET_SILENT)
            !isFilteringEnabled() && isMediaControlsEnabled() ->
                intArrayOf(BUCKET_HEADS_UP, BUCKET_MEDIA_CONTROLS, BUCKET_ALERTING, BUCKET_SILENT)
                intArrayOf(BUCKET_HEADS_UP, BUCKET_FOREGROUND_SERVICE, BUCKET_MEDIA_CONTROLS,
                        BUCKET_ALERTING, BUCKET_SILENT)
            isFilteringEnabled() && !isMediaControlsEnabled() ->
                intArrayOf(BUCKET_HEADS_UP, BUCKET_PEOPLE, BUCKET_ALERTING, BUCKET_SILENT)
                intArrayOf(BUCKET_HEADS_UP, BUCKET_FOREGROUND_SERVICE, BUCKET_PEOPLE,
                        BUCKET_ALERTING, BUCKET_SILENT)
            NotificationUtils.useNewInterruptionModel(context) ->
                intArrayOf(BUCKET_ALERTING, BUCKET_SILENT)
            else ->
+3 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import com.android.systemui.statusbar.notification.collection.provider.HighPrior
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_NON_PERSON
import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING
import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_FOREGROUND_SERVICE
import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_HEADS_UP
import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_PEOPLE
import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_SILENT
@@ -162,6 +163,8 @@ open class NotificationRankingManager @Inject constructor(
        val isMedia = isImportantMedia(entry)
        val isSystemMax = entry.isSystemMax()
        return when {
            entry.sbn.notification.isForegroundService && entry.sbn.notification.isColorized ->
                BUCKET_FOREGROUND_SERVICE
            usePeopleFiltering && entry.getPeopleNotificationType() != TYPE_NON_PERSON ->
                BUCKET_PEOPLE
            isHeadsUp || isMedia || isSystemMax || entry.isHighPriority() ->
+28 −35
Original line number Diff line number Diff line
@@ -29,12 +29,10 @@ import android.content.Intent;
import android.provider.Settings;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.R;
import com.android.systemui.media.KeyguardMediaController;
import com.android.systemui.media.MediaHierarchyManager;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.StatusBarState;
@@ -329,8 +327,6 @@ public class NotificationSectionsManager implements StackScrollAlgorithm.Section
        boolean peopleNotifsPresent = false;

        int currentMediaControlsIdx = -1;
        // Currently, just putting media controls in the front and incrementing the position based
        // on the number of heads-up notifs.
        int mediaControlsTarget = usingMediaControls ? 0 : -1;
        int currentIncomingHeaderIdx = -1;
        int incomingHeaderTarget = -1;
@@ -408,6 +404,11 @@ public class NotificationSectionsManager implements StackScrollAlgorithm.Section
                        mediaControlsTarget++;
                    }
                    break;
                case BUCKET_FOREGROUND_SERVICE:
                    if (mediaControlsTarget != -1) {
                        mediaControlsTarget++;
                    }
                    break;
                case BUCKET_PEOPLE:
                    mLogger.logPosition(i, "Conversation");
                    peopleNotifsPresent = true;
@@ -488,7 +489,8 @@ public class NotificationSectionsManager implements StackScrollAlgorithm.Section
        adjustHeaderVisibilityAndPosition(
                peopleHeaderTarget, mPeopleHubView, currentPeopleHeaderIdx);
        adjustViewPosition(mediaControlsTarget, mMediaControlsView, currentMediaControlsIdx);
        adjustViewPosition(incomingHeaderTarget, mIncomingHeader, currentIncomingHeaderIdx);
        adjustHeaderVisibilityAndPosition(incomingHeaderTarget, mIncomingHeader,
                currentIncomingHeaderIdx);


        mLogger.logStr("Final order:");
@@ -508,45 +510,29 @@ public class NotificationSectionsManager implements StackScrollAlgorithm.Section

    private void adjustHeaderVisibilityAndPosition(
            int targetPosition, StackScrollerDecorView header, int currentPosition) {
        if (targetPosition == -1) {
            if (currentPosition != -1) {
                mParent.removeView(header);
            }
        } else {
            if (currentPosition == -1) {
                // If the header is animating away, it will still have a parent, so detach it first
                // TODO: We should really cancel the active animations here. This will happen
                // automatically when the view's intro animation starts, but it's a fragile link.
                if (header.getTransientContainer() != null) {
                    header.getTransientContainer().removeTransientView(header);
                    header.setTransientContainer(null);
                }
        adjustViewPosition(targetPosition, header, currentPosition);
        if (targetPosition != -1 && currentPosition == -1) {
            header.setContentVisible(true);
                mParent.addView(header, targetPosition);
            } else {
                mParent.changeViewPosition(header, targetPosition);
            }
        }
    }

    private void adjustViewPosition(int targetPosition, ExpandableView header,
            int currentPosition) {
    private void adjustViewPosition(int targetPosition, ExpandableView view, int currentPosition) {
        if (targetPosition == -1) {
            if (currentPosition != -1) {
                mParent.removeView(header);
                mParent.removeView(view);
            }
        } else {
            if (currentPosition == -1) {
                // If the header is animating away, it will still have a parent, so detach it first
                // TODO: We should really cancel the active animations here. This will happen
                // automatically when the view's intro animation starts, but it's a fragile link.
                if (header.getTransientContainer() != null) {
                    header.getTransientContainer().removeTransientView(header);
                    header.setTransientContainer(null);
                if (view.getTransientContainer() != null) {
                    view.getTransientContainer().removeTransientView(view);
                    view.setTransientContainer(null);
                }
                mParent.addView(header, targetPosition);
                mParent.addView(view, targetPosition);
            } else {
                mParent.changeViewPosition(header, targetPosition);
                mParent.changeViewPosition(view, targetPosition);
            }
        }
    }
@@ -640,6 +626,11 @@ public class NotificationSectionsManager implements StackScrollAlgorithm.Section
        return mMediaControlsView;
    }

    @VisibleForTesting
    ExpandableView getIncomingHeaderView() {
        return mIncomingHeader;
    }

    @VisibleForTesting
    void setPeopleHubVisible(boolean visible) {
        mPeopleHubVisible = visible;
@@ -685,6 +676,7 @@ public class NotificationSectionsManager implements StackScrollAlgorithm.Section
    @Retention(SOURCE)
    @IntDef(prefix = { "BUCKET_" }, value = {
            BUCKET_HEADS_UP,
            BUCKET_FOREGROUND_SERVICE,
            BUCKET_MEDIA_CONTROLS,
            BUCKET_PEOPLE,
            BUCKET_ALERTING,
@@ -692,8 +684,9 @@ public class NotificationSectionsManager implements StackScrollAlgorithm.Section
    })
    public @interface PriorityBucket {}
    public static final int BUCKET_HEADS_UP = 0;
    public static final int BUCKET_MEDIA_CONTROLS = 1;
    public static final int BUCKET_PEOPLE = 2;
    public static final int BUCKET_ALERTING = 3;
    public static final int BUCKET_SILENT = 4;
    public static final int BUCKET_FOREGROUND_SERVICE = 1;
    public static final int BUCKET_MEDIA_CONTROLS = 2;
    public static final int BUCKET_PEOPLE = 3;
    public static final int BUCKET_ALERTING = 4;
    public static final int BUCKET_SILENT = 5;
}
+211 −11
Original line number Diff line number Diff line
@@ -19,15 +19,19 @@ package com.android.systemui.statusbar.notification.stack;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;

import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING;
import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_FOREGROUND_SERVICE;
import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_HEADS_UP;
import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_PEOPLE;
import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_SILENT;

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

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@@ -62,6 +66,9 @@ import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;

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

@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
@@ -84,10 +91,23 @@ public class NotificationSectionsManagerTest extends SysuiTestCase {

    @Before
    public void setUp() {
        when(mSectionsFeatureManager.getNumberOfBuckets()).thenReturn(2);
        when(mNotificationRowComponent.getActivatableNotificationViewController()).thenReturn(
                mActivatableNotificationViewController
        );
        when(mSectionsFeatureManager.getNumberOfBuckets()).thenAnswer(
                invocation -> {
                    int count = 2;
                    if (mSectionsFeatureManager.isFilteringEnabled()) {
                        count = 5;
                    }
                    if (mSectionsFeatureManager.isMediaControlsEnabled()) {
                        if (!mSectionsFeatureManager.isFilteringEnabled()) {
                            count = 5;
                        } else {
                            count += 1;
                        }
                    }
                    return count;
                });
        when(mNotificationRowComponent.getActivatableNotificationViewController())
                .thenReturn(mActivatableNotificationViewController);
        mSectionsManager =
                new NotificationSectionsManager(
                        mActivityStarterDelegate,
@@ -104,6 +124,7 @@ public class NotificationSectionsManagerTest extends SysuiTestCase {
        mSectionsManager.initialize(mNssl, LayoutInflater.from(mContext));
        when(mNssl.indexOfChild(any(View.class))).thenReturn(-1);
        when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);

    }

    @Test(expected =  IllegalStateException.class)
@@ -338,6 +359,58 @@ public class NotificationSectionsManagerTest extends SysuiTestCase {
        verify(mNssl).changeViewPosition(mSectionsManager.getPeopleHeaderView(), 0);
    }

    @Test
    public void testPeopleFiltering_HunWhilePeopleVisible() {
        enablePeopleFiltering();

        setupMockStack(
                ChildType.PEOPLE_HEADER,
                ChildType.HEADS_UP,
                ChildType.PERSON,
                ChildType.ALERTING_HEADER,
                ChildType.GENTLE_HEADER,
                ChildType.GENTLE
        );
        mSectionsManager.updateSectionBoundaries();

        verifyMockStack(
                ChildType.INCOMING_HEADER,
                ChildType.HEADS_UP,
                ChildType.PEOPLE_HEADER,
                ChildType.PERSON,
                ChildType.GENTLE_HEADER,
                ChildType.GENTLE
        );
    }

    @Test
    public void testPeopleFiltering_Fsn() {
        enablePeopleFiltering();

        setupMockStack(
                ChildType.INCOMING_HEADER,
                ChildType.HEADS_UP,
                ChildType.PEOPLE_HEADER,
                ChildType.FSN,
                ChildType.PERSON,
                ChildType.ALERTING,
                ChildType.GENTLE
        );
        mSectionsManager.updateSectionBoundaries();

        verifyMockStack(
                ChildType.INCOMING_HEADER,
                ChildType.HEADS_UP,
                ChildType.FSN,
                ChildType.PEOPLE_HEADER,
                ChildType.PERSON,
                ChildType.ALERTING_HEADER,
                ChildType.ALERTING,
                ChildType.GENTLE_HEADER,
                ChildType.GENTLE
        );
    }

    @Test
    public void testMediaControls_AddWhenEnterKeyguard() {
        enableMediaControls();
@@ -358,30 +431,28 @@ public class NotificationSectionsManagerTest extends SysuiTestCase {
        enableMediaControls();

        // GIVEN a stack that doesn't include media controls but includes HEADS_UP
        setStackState(ChildType.HEADS_UP, ChildType.ALERTING, ChildType.GENTLE_HEADER,
        setupMockStack(ChildType.HEADS_UP, ChildType.ALERTING, ChildType.GENTLE_HEADER,
                ChildType.GENTLE);

        // WHEN we go back to the keyguard
        when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD);
        mSectionsManager.updateSectionBoundaries();

        // Then the media controls are added after HEADS_UP
        verify(mNssl).addView(mSectionsManager.getMediaControlsView(), 1);
        verifyMockStack(ChildType.HEADS_UP, ChildType.MEDIA_CONTROLS, ChildType.ALERTING,
                ChildType.GENTLE);
    }

    private void enablePeopleFiltering() {
        when(mSectionsFeatureManager.isFilteringEnabled()).thenReturn(true);
        when(mSectionsFeatureManager.getNumberOfBuckets()).thenReturn(4);
    }

    private void enableMediaControls() {
        when(mSectionsFeatureManager.isMediaControlsEnabled()).thenReturn(true);
        when(mSectionsFeatureManager.getNumberOfBuckets()).thenReturn(4);
    }

    private enum ChildType {
        MEDIA_CONTROLS, PEOPLE_HEADER, ALERTING_HEADER, GENTLE_HEADER, HEADS_UP, PERSON, ALERTING,
            GENTLE, OTHER
        INCOMING_HEADER, MEDIA_CONTROLS, PEOPLE_HEADER, ALERTING_HEADER, GENTLE_HEADER, HEADS_UP,
        FSN, PERSON, ALERTING, GENTLE, OTHER
    }

    private void setStackState(ChildType... children) {
@@ -389,6 +460,9 @@ public class NotificationSectionsManagerTest extends SysuiTestCase {
        for (int i = 0; i < children.length; i++) {
            View child;
            switch (children[i]) {
                case INCOMING_HEADER:
                    child = mSectionsManager.getIncomingHeaderView();
                    break;
                case MEDIA_CONTROLS:
                    child = mSectionsManager.getMediaControlsView();
                    break;
@@ -404,6 +478,9 @@ public class NotificationSectionsManagerTest extends SysuiTestCase {
                case HEADS_UP:
                    child = mockNotification(BUCKET_HEADS_UP);
                    break;
                case FSN:
                    child = mockNotification(BUCKET_FOREGROUND_SERVICE);
                    break;
                case PERSON:
                    child = mockNotification(BUCKET_PEOPLE);
                    break;
@@ -434,4 +511,127 @@ public class NotificationSectionsManagerTest extends SysuiTestCase {
        when(notifRow.getParent()).thenReturn(mNssl);
        return notifRow;
    }

    private void verifyMockStack(ChildType... expected) {
        final List<ChildType> actual = new ArrayList<>();
        int childCount = mNssl.getChildCount();
        for (int i = 0; i < childCount; i++) {
            View child = mNssl.getChildAt(i);
            if (child == mSectionsManager.getIncomingHeaderView()) {
                actual.add(ChildType.INCOMING_HEADER);
                continue;
            }
            if (child == mSectionsManager.getMediaControlsView()) {
                actual.add(ChildType.MEDIA_CONTROLS);
                continue;
            }
            if (child == mSectionsManager.getPeopleHeaderView()) {
                actual.add(ChildType.PEOPLE_HEADER);
                continue;
            }
            if (child == mSectionsManager.getAlertingHeaderView()) {
                actual.add(ChildType.ALERTING_HEADER);
                continue;
            }
            if (child == mSectionsManager.getGentleHeaderView()) {
                actual.add(ChildType.GENTLE_HEADER);
                continue;
            }
            if (child instanceof ExpandableNotificationRow) {
                switch (((ExpandableNotificationRow) child).getEntry().getBucket()) {
                    case BUCKET_HEADS_UP:
                        actual.add(ChildType.HEADS_UP);
                        break;
                    case BUCKET_FOREGROUND_SERVICE:
                        actual.add(ChildType.FSN);
                        break;
                    case BUCKET_PEOPLE:
                        actual.add(ChildType.PERSON);
                        break;
                    case BUCKET_ALERTING:
                        actual.add(ChildType.ALERTING);
                        break;
                    case BUCKET_SILENT:
                        actual.add(ChildType.GENTLE);
                        break;
                    default:
                        actual.add(ChildType.OTHER);
                        break;
                }
                continue;
            }
            actual.add(ChildType.OTHER);
        }
        assertThat(actual).containsExactly((Object[]) expected).inOrder();
    }

    private void setupMockStack(ChildType... childTypes) {
        final List<View> children = new ArrayList<>();
        when(mNssl.getChildCount()).thenAnswer(invocation -> children.size());
        when(mNssl.getChildAt(anyInt()))
                .thenAnswer(invocation -> children.get(invocation.getArgument(0)));
        when(mNssl.indexOfChild(any()))
                .thenAnswer(invocation -> children.indexOf(invocation.getArgument(0)));
        doAnswer(invocation -> {
            View child = invocation.getArgument(0);
            int index = invocation.getArgument(1);
            children.add(index, child);
            return null;
        }).when(mNssl).addView(any(), anyInt());
        doAnswer(invocation -> {
            View child = invocation.getArgument(0);
            children.remove(child);
            return null;
        }).when(mNssl).removeView(any());
        doAnswer(invocation -> {
            View child = invocation.getArgument(0);
            int newIndex = invocation.getArgument(1);
            children.remove(child);
            children.add(newIndex, child);
            return null;
        }).when(mNssl).changeViewPosition(any(), anyInt());
        for (ChildType childType : childTypes) {
            View child;
            switch (childType) {
                case INCOMING_HEADER:
                    child = mSectionsManager.getIncomingHeaderView();
                    break;
                case MEDIA_CONTROLS:
                    child = mSectionsManager.getMediaControlsView();
                    break;
                case PEOPLE_HEADER:
                    child = mSectionsManager.getPeopleHeaderView();
                    break;
                case ALERTING_HEADER:
                    child = mSectionsManager.getAlertingHeaderView();
                    break;
                case GENTLE_HEADER:
                    child = mSectionsManager.getGentleHeaderView();
                    break;
                case HEADS_UP:
                    child = mockNotification(BUCKET_HEADS_UP);
                    break;
                case FSN:
                    child = mockNotification(BUCKET_FOREGROUND_SERVICE);
                    break;
                case PERSON:
                    child = mockNotification(BUCKET_PEOPLE);
                    break;
                case ALERTING:
                    child = mockNotification(BUCKET_ALERTING);
                    break;
                case GENTLE:
                    child = mockNotification(BUCKET_SILENT);
                    break;
                case OTHER:
                    child = mock(View.class);
                    when(child.getVisibility()).thenReturn(View.VISIBLE);
                    when(child.getParent()).thenReturn(mNssl);
                    break;
                default:
                    throw new RuntimeException("Unknown ChildType: " + childType);
            }
            children.add(child);
        }
    }
}