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

Commit 8f034348 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Update section header placement logic" into rvc-dev

parents fde0af91 35956b45
Loading
Loading
Loading
Loading
+124 −69
Original line number Original line Diff line number Diff line
@@ -16,6 +16,8 @@


package com.android.systemui.statusbar.notification.stack;
package com.android.systemui.statusbar.notification.stack;


import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_GENTLE;

import static java.lang.annotation.RetentionPolicy.SOURCE;
import static java.lang.annotation.RetentionPolicy.SOURCE;


import android.annotation.IntDef;
import android.annotation.IntDef;
@@ -100,14 +102,11 @@ public class NotificationSectionsManager implements StackScrollAlgorithm.Section
    private boolean mInitialized = false;
    private boolean mInitialized = false;


    private SectionHeaderView mGentleHeader;
    private SectionHeaderView mGentleHeader;
    private boolean mGentleHeaderVisible;
    @Nullable private View.OnClickListener mOnClearGentleNotifsClickListener;
    @Nullable private View.OnClickListener mOnClearGentleNotifsClickListener;


    private SectionHeaderView mAlertingHeader;
    private SectionHeaderView mAlertingHeader;
    private boolean mAlertingHeaderVisible;


    private PeopleHubView mPeopleHubView;
    private PeopleHubView mPeopleHubView;
    private boolean mPeopleHeaderVisible;
    private boolean mPeopleHubVisible = false;
    private boolean mPeopleHubVisible = false;
    @Nullable private Subscription mPeopleHubSubscription;
    @Nullable private Subscription mPeopleHubSubscription;


@@ -231,88 +230,135 @@ public class NotificationSectionsManager implements StackScrollAlgorithm.Section
            return;
            return;
        }
        }


        // The overall strategy here is to iterate over the current children of mParent, looking
        // for where the sections headers are currently positioned, and where each section begins.
        // Then, once we find the start of a new section, we track that position as the "target" for
        // the section header, adjusted for the case where existing headers are in front of that
        // target, but won't be once they are moved / removed after the pass has completed.

        final boolean showHeaders = mStatusBarStateController.getState() != StatusBarState.KEYGUARD;
        final boolean showHeaders = mStatusBarStateController.getState() != StatusBarState.KEYGUARD;
        final boolean usingPeopleFiltering = mSectionsFeatureManager.isFilteringEnabled();
        final boolean usingPeopleFiltering = mSectionsFeatureManager.isFilteringEnabled();


        boolean peopleNotifsPresent = false;
        boolean peopleNotifsPresent = false;

        int currentPeopleHeaderIdx = -1;
        int peopleHeaderTarget = -1;
        int peopleHeaderTarget = -1;
        int currentAlertingHeaderIdx = -1;
        int alertingHeaderTarget = -1;
        int alertingHeaderTarget = -1;
        int currentGentleHeaderIdx = -1;
        int gentleHeaderTarget = -1;
        int gentleHeaderTarget = -1;


        int viewCount = 0;
        int lastNotifIndex = 0;


        if (showHeaders) {
        final int childCount = mParent.getChildCount();
        final int childCount = mParent.getChildCount();
        for (int i = 0; i < childCount; i++) {
        for (int i = 0; i < childCount; i++) {
            View child = mParent.getChildAt(i);
            View child = mParent.getChildAt(i);
                if (child.getVisibility() == View.GONE

                        || !(child instanceof ExpandableNotificationRow)) {
            // Track the existing positions of the headers
            if (child == mPeopleHubView) {
                currentPeopleHeaderIdx = i;
                continue;
            }
            if (child == mAlertingHeader) {
                currentAlertingHeaderIdx = i;
                continue;
            }
            if (child == mGentleHeader) {
                currentGentleHeaderIdx = i;
                continue;
                continue;
            }
            }

            if (!(child instanceof ExpandableNotificationRow)) {
                continue;
            }
            lastNotifIndex = i;
            ExpandableNotificationRow row = (ExpandableNotificationRow) child;
            ExpandableNotificationRow row = (ExpandableNotificationRow) child;
            // Once we enter a new section, calculate the target position for the header.
            switch (row.getEntry().getBucket()) {
            switch (row.getEntry().getBucket()) {
                case BUCKET_HEADS_UP:
                    break;
                case BUCKET_PEOPLE:
                case BUCKET_PEOPLE:
                        if (peopleHeaderTarget == -1) {
                    peopleNotifsPresent = true;
                    peopleNotifsPresent = true;
                            peopleHeaderTarget = viewCount;
                    if (showHeaders && peopleHeaderTarget == -1) {
                            viewCount++;
                        peopleHeaderTarget = i;
                        // Offset the target if there are other headers before this that will be
                        // moved.
                        if (currentPeopleHeaderIdx != -1) {
                            peopleHeaderTarget--;
                        }
                        if (currentAlertingHeaderIdx != -1) {
                            peopleHeaderTarget--;
                        }
                        if (currentGentleHeaderIdx != -1) {
                            peopleHeaderTarget--;
                        }
                    }
                    }
                    break;
                    break;
                case BUCKET_ALERTING:
                case BUCKET_ALERTING:
                        if (usingPeopleFiltering && alertingHeaderTarget == -1) {
                    if (showHeaders && usingPeopleFiltering && alertingHeaderTarget == -1) {
                            alertingHeaderTarget = viewCount;
                        alertingHeaderTarget = i;
                            viewCount++;
                        // Offset the target if there are other headers before this that will be
                        // moved.
                        if (currentAlertingHeaderIdx != -1) {
                            alertingHeaderTarget--;
                        }
                        if (currentGentleHeaderIdx != -1) {
                            alertingHeaderTarget--;
                        }
                    }
                    }
                    break;
                    break;
                case BUCKET_SILENT:
                case BUCKET_SILENT:
                        if (gentleHeaderTarget == -1) {
                    if (showHeaders && gentleHeaderTarget == -1) {
                            gentleHeaderTarget = viewCount;
                        gentleHeaderTarget = i;
                            viewCount++;
                        // Offset the target if there are other headers before this that will be
                        // moved.
                        if (currentGentleHeaderIdx != -1) {
                            gentleHeaderTarget--;
                        }
                    }
                    }
                    break;
                    break;
                default:
                    throw new IllegalStateException("Cannot find section bucket for view");
            }
            }
                viewCount++;
        }
        }
            if (usingPeopleFiltering && mPeopleHubVisible && peopleHeaderTarget == -1) {
        if (showHeaders && usingPeopleFiltering && mPeopleHubVisible && peopleHeaderTarget == -1) {
            // Insert the people header even if there are no people visible, in order to show
            // Insert the people header even if there are no people visible, in order to show
            // the hub. Put it directly above the next header.
            // the hub. Put it directly above the next header.
            if (alertingHeaderTarget != -1) {
            if (alertingHeaderTarget != -1) {
                peopleHeaderTarget = alertingHeaderTarget;
                peopleHeaderTarget = alertingHeaderTarget;
                    alertingHeaderTarget++;
                    gentleHeaderTarget++;
            } else if (gentleHeaderTarget != -1) {
            } else if (gentleHeaderTarget != -1) {
                peopleHeaderTarget = gentleHeaderTarget;
                peopleHeaderTarget = gentleHeaderTarget;
                    gentleHeaderTarget++;
            } else {
            } else {
                // Put it at the end of the list.
                // Put it at the end of the list.
                    peopleHeaderTarget = viewCount;
                peopleHeaderTarget = lastNotifIndex;
                }
            }
            }
        }
        }


        // Allow swiping the people header if the section is empty
        // Add headers in reverse order to preserve indices
        mPeopleHubView.setCanSwipe(mPeopleHubVisible && !peopleNotifsPresent);
        adjustHeaderVisibilityAndPosition(
                gentleHeaderTarget, mGentleHeader, currentGentleHeaderIdx);
        adjustHeaderVisibilityAndPosition(
                alertingHeaderTarget, mAlertingHeader, currentAlertingHeaderIdx);
        adjustHeaderVisibilityAndPosition(
                peopleHeaderTarget, mPeopleHubView, currentPeopleHeaderIdx);


        mPeopleHeaderVisible = adjustHeaderVisibilityAndPosition(
        // Update headers to reflect state of section contents
                peopleHeaderTarget, mPeopleHubView, mPeopleHeaderVisible);
        mGentleHeader.setAreThereDismissableGentleNotifs(
        mAlertingHeaderVisible = adjustHeaderVisibilityAndPosition(
                mParent.hasActiveClearableNotifications(ROWS_GENTLE));
                alertingHeaderTarget, mAlertingHeader, mAlertingHeaderVisible);
        mPeopleHubView.setCanSwipe(showHeaders && mPeopleHubVisible && !peopleNotifsPresent);
        mGentleHeaderVisible = adjustHeaderVisibilityAndPosition(
        if (peopleHeaderTarget != currentPeopleHeaderIdx) {
                gentleHeaderTarget, mGentleHeader, mGentleHeaderVisible);
            mPeopleHubView.resetTranslation();
        }
    }
    }


    private boolean adjustHeaderVisibilityAndPosition(
    private void adjustHeaderVisibilityAndPosition(
            int targetIndex, StackScrollerDecorView header, boolean isCurrentlyVisible) {
            int targetPosition, StackScrollerDecorView header, int currentPosition) {
        if (targetIndex == -1) {
        if (targetPosition == -1) {
            if (isCurrentlyVisible) {
            if (currentPosition != -1) {
                mParent.removeView(header);
                mParent.removeView(header);
            }
            }
            return false;
        } else {
        } else {
            if (header instanceof SwipeableView) {
            if (currentPosition == -1) {
                ((SwipeableView) header).resetTranslation();
            }
            if (!isCurrentlyVisible) {
                // If the header is animating away, it will still have a parent, so detach it first
                // 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
                // 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.
                // automatically when the view's intro animation starts, but it's a fragile link.
@@ -321,11 +367,10 @@ public class NotificationSectionsManager implements StackScrollAlgorithm.Section
                    header.setTransientContainer(null);
                    header.setTransientContainer(null);
                }
                }
                header.setContentVisible(true);
                header.setContentVisible(true);
                mParent.addView(header, targetIndex);
                mParent.addView(header, targetPosition);
            } else if (mParent.indexOfChild(header) != targetIndex) {
            } else {
                mParent.changeViewPosition(header, targetIndex);
                mParent.changeViewPosition(header, targetPosition);
            }
            }
            return true;
        }
        }
    }
    }


@@ -400,10 +445,20 @@ public class NotificationSectionsManager implements StackScrollAlgorithm.Section




    @VisibleForTesting
    @VisibleForTesting
    SectionHeaderView getGentleHeaderView() {
    ExpandableView getGentleHeaderView() {
        return mGentleHeader;
        return mGentleHeader;
    }
    }


    @VisibleForTesting
    ExpandableView getAlertingHeaderView() {
        return mAlertingHeader;
    }

    @VisibleForTesting
    ExpandableView getPeopleHeaderView() {
        return mPeopleHubView;
    }

    private final ConfigurationListener mConfigurationListener = new ConfigurationListener() {
    private final ConfigurationListener mConfigurationListener = new ConfigurationListener() {
        @Override
        @Override
        public void onLocaleListChanged() {
        public void onLocaleListChanged() {
+129 −47
Original line number Original line Diff line number Diff line
@@ -19,6 +19,8 @@ package com.android.systemui.statusbar.notification.stack;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
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_ALERTING;
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.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_SILENT;


import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.any;
@@ -107,7 +109,7 @@ public class NotificationSectionsManagerTest extends SysuiTestCase {
    @Test
    @Test
    public void testInsertHeader() {
    public void testInsertHeader() {
        // GIVEN a stack with HI and LO rows but no section headers
        // GIVEN a stack with HI and LO rows but no section headers
        setStackState(ChildType.HIPRI, ChildType.HIPRI, ChildType.HIPRI, ChildType.LOPRI);
        setStackState(ChildType.ALERTING, ChildType.ALERTING, ChildType.ALERTING, ChildType.GENTLE);


        // WHEN we update the section headers
        // WHEN we update the section headers
        mSectionsManager.updateSectionBoundaries();
        mSectionsManager.updateSectionBoundaries();
@@ -119,11 +121,15 @@ public class NotificationSectionsManagerTest extends SysuiTestCase {
    @Test
    @Test
    public void testRemoveHeader() {
    public void testRemoveHeader() {
        // GIVEN a stack that originally had a header between the HI and LO sections
        // GIVEN a stack that originally had a header between the HI and LO sections
        setStackState(ChildType.HIPRI, ChildType.HIPRI, ChildType.LOPRI);
        setStackState(ChildType.ALERTING, ChildType.ALERTING, ChildType.GENTLE);
        mSectionsManager.updateSectionBoundaries();
        mSectionsManager.updateSectionBoundaries();


        // WHEN the last LO row is replaced with a HI row
        // WHEN the last LO row is replaced with a HI row
        setStackState(ChildType.HIPRI, ChildType.HIPRI, ChildType.HEADER, ChildType.HIPRI);
        setStackState(
                ChildType.ALERTING,
                ChildType.ALERTING,
                ChildType.GENTLE_HEADER,
                ChildType.ALERTING);
        clearInvocations(mNssl);
        clearInvocations(mNssl);
        mSectionsManager.updateSectionBoundaries();
        mSectionsManager.updateSectionBoundaries();


@@ -134,7 +140,7 @@ public class NotificationSectionsManagerTest extends SysuiTestCase {
    @Test
    @Test
    public void testDoNothingIfHeaderAlreadyRemoved() {
    public void testDoNothingIfHeaderAlreadyRemoved() {
        // GIVEN a stack with only HI rows
        // GIVEN a stack with only HI rows
        setStackState(ChildType.HIPRI, ChildType.HIPRI, ChildType.HIPRI);
        setStackState(ChildType.ALERTING, ChildType.ALERTING, ChildType.ALERTING);


        // WHEN we update the sections headers
        // WHEN we update the sections headers
        mSectionsManager.updateSectionBoundaries();
        mSectionsManager.updateSectionBoundaries();
@@ -147,19 +153,19 @@ public class NotificationSectionsManagerTest extends SysuiTestCase {
    public void testMoveHeaderForward() {
    public void testMoveHeaderForward() {
        // GIVEN a stack that originally had a header between the HI and LO sections
        // GIVEN a stack that originally had a header between the HI and LO sections
        setStackState(
        setStackState(
                ChildType.HIPRI,
                ChildType.ALERTING,
                ChildType.HIPRI,
                ChildType.ALERTING,
                ChildType.HIPRI,
                ChildType.ALERTING,
                ChildType.LOPRI);
                ChildType.GENTLE);
        mSectionsManager.updateSectionBoundaries();
        mSectionsManager.updateSectionBoundaries();


        // WHEN the LO section moves forward
        // WHEN the LO section moves forward
        setStackState(
        setStackState(
                ChildType.HIPRI,
                ChildType.ALERTING,
                ChildType.HIPRI,
                ChildType.ALERTING,
                ChildType.LOPRI,
                ChildType.GENTLE,
                ChildType.HEADER,
                ChildType.GENTLE_HEADER,
                ChildType.LOPRI);
                ChildType.GENTLE);
        mSectionsManager.updateSectionBoundaries();
        mSectionsManager.updateSectionBoundaries();


        // THEN the LO section header is also moved forward
        // THEN the LO section header is also moved forward
@@ -170,19 +176,19 @@ public class NotificationSectionsManagerTest extends SysuiTestCase {
    public void testMoveHeaderBackward() {
    public void testMoveHeaderBackward() {
        // GIVEN a stack that originally had a header between the HI and LO sections
        // GIVEN a stack that originally had a header between the HI and LO sections
        setStackState(
        setStackState(
                ChildType.HIPRI,
                ChildType.ALERTING,
                ChildType.LOPRI,
                ChildType.GENTLE,
                ChildType.LOPRI,
                ChildType.GENTLE,
                ChildType.LOPRI);
                ChildType.GENTLE);
        mSectionsManager.updateSectionBoundaries();
        mSectionsManager.updateSectionBoundaries();


        // WHEN the LO section moves backward
        // WHEN the LO section moves backward
        setStackState(
        setStackState(
                ChildType.HIPRI,
                ChildType.ALERTING,
                ChildType.HEADER,
                ChildType.GENTLE_HEADER,
                ChildType.HIPRI,
                ChildType.ALERTING,
                ChildType.HIPRI,
                ChildType.ALERTING,
                ChildType.LOPRI);
                ChildType.GENTLE);
        mSectionsManager.updateSectionBoundaries();
        mSectionsManager.updateSectionBoundaries();


        // THEN the LO section header is also moved backward (with appropriate index shifting)
        // THEN the LO section header is also moved backward (with appropriate index shifting)
@@ -193,14 +199,14 @@ public class NotificationSectionsManagerTest extends SysuiTestCase {
    public void testHeaderRemovedFromTransientParent() {
    public void testHeaderRemovedFromTransientParent() {
        // GIVEN a stack where the header is animating away
        // GIVEN a stack where the header is animating away
        setStackState(
        setStackState(
                ChildType.HIPRI,
                ChildType.ALERTING,
                ChildType.LOPRI,
                ChildType.GENTLE,
                ChildType.LOPRI,
                ChildType.GENTLE,
                ChildType.LOPRI);
                ChildType.GENTLE);
        mSectionsManager.updateSectionBoundaries();
        mSectionsManager.updateSectionBoundaries();
        setStackState(
        setStackState(
                ChildType.HIPRI,
                ChildType.ALERTING,
                ChildType.HEADER);
                ChildType.GENTLE_HEADER);
        mSectionsManager.updateSectionBoundaries();
        mSectionsManager.updateSectionBoundaries();
        clearInvocations(mNssl);
        clearInvocations(mNssl);


@@ -209,8 +215,8 @@ public class NotificationSectionsManagerTest extends SysuiTestCase {


        // WHEN the LO section reappears
        // WHEN the LO section reappears
        setStackState(
        setStackState(
                ChildType.HIPRI,
                ChildType.ALERTING,
                ChildType.LOPRI);
                ChildType.GENTLE);
        mSectionsManager.updateSectionBoundaries();
        mSectionsManager.updateSectionBoundaries();


        // THEN the header is first removed from the transient parent before being added to the
        // THEN the header is first removed from the transient parent before being added to the
@@ -223,7 +229,7 @@ public class NotificationSectionsManagerTest extends SysuiTestCase {
    public void testHeaderNotShownOnLockscreen() {
    public void testHeaderNotShownOnLockscreen() {
        // GIVEN a stack of HI and LO notifs on the lockscreen
        // GIVEN a stack of HI and LO notifs on the lockscreen
        when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD);
        when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD);
        setStackState(ChildType.HIPRI, ChildType.HIPRI, ChildType.HIPRI, ChildType.LOPRI);
        setStackState(ChildType.ALERTING, ChildType.ALERTING, ChildType.ALERTING, ChildType.GENTLE);


        // WHEN we update the section headers
        // WHEN we update the section headers
        mSectionsManager.updateSectionBoundaries();
        mSectionsManager.updateSectionBoundaries();
@@ -236,7 +242,7 @@ public class NotificationSectionsManagerTest extends SysuiTestCase {
    public void testHeaderShownWhenEnterLockscreen() {
    public void testHeaderShownWhenEnterLockscreen() {
        // GIVEN a stack of HI and LO notifs on the lockscreen
        // GIVEN a stack of HI and LO notifs on the lockscreen
        when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD);
        when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD);
        setStackState(ChildType.HIPRI, ChildType.HIPRI, ChildType.HIPRI, ChildType.LOPRI);
        setStackState(ChildType.ALERTING, ChildType.ALERTING, ChildType.ALERTING, ChildType.GENTLE);
        mSectionsManager.updateSectionBoundaries();
        mSectionsManager.updateSectionBoundaries();


        // WHEN we unlock
        // WHEN we unlock
@@ -250,37 +256,104 @@ public class NotificationSectionsManagerTest extends SysuiTestCase {
    @Test
    @Test
    public void testHeaderHiddenWhenEnterLockscreen() {
    public void testHeaderHiddenWhenEnterLockscreen() {
        // GIVEN a stack of HI and LO notifs on the shade
        // GIVEN a stack of HI and LO notifs on the shade
        when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE_LOCKED);
        setStackState(ChildType.ALERTING, ChildType.GENTLE_HEADER, ChildType.GENTLE);
        setStackState(ChildType.HIPRI, ChildType.HIPRI, ChildType.HIPRI, ChildType.LOPRI);
        mSectionsManager.updateSectionBoundaries();


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


        // Then the section header is removed
        // Then the section header is removed
        verify(mNssl).removeView(eq(mSectionsManager.getGentleHeaderView()));
        verify(mNssl).removeView(mSectionsManager.getGentleHeaderView());
    }

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

        setStackState(
                ChildType.GENTLE_HEADER,
                ChildType.PERSON,
                ChildType.ALERTING,
                ChildType.GENTLE);
        mSectionsManager.updateSectionBoundaries();

        verify(mNssl).changeViewPosition(mSectionsManager.getGentleHeaderView(), 2);
        verify(mNssl).addView(mSectionsManager.getAlertingHeaderView(), 1);
        verify(mNssl).addView(mSectionsManager.getPeopleHeaderView(), 0);
    }

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

        setStackState(
                ChildType.PERSON,
                ChildType.ALERTING,
                ChildType.GENTLE);
        mSectionsManager.updateSectionBoundaries();

        verify(mNssl).addView(mSectionsManager.getGentleHeaderView(), 2);
        verify(mNssl).addView(mSectionsManager.getAlertingHeaderView(), 1);
        verify(mNssl).addView(mSectionsManager.getPeopleHeaderView(), 0);
    }

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

        setStackState(
                ChildType.PEOPLE_HEADER,
                ChildType.ALERTING_HEADER,
                ChildType.GENTLE_HEADER,
                ChildType.PERSON,
                ChildType.ALERTING,
                ChildType.GENTLE);
        mSectionsManager.updateSectionBoundaries();

        verify(mNssl).changeViewPosition(mSectionsManager.getGentleHeaderView(), 4);
        verify(mNssl).changeViewPosition(mSectionsManager.getAlertingHeaderView(), 2);
        verify(mNssl).changeViewPosition(mSectionsManager.getPeopleHeaderView(), 0);
    }
    }


    private enum ChildType { HEADER, HIPRI, LOPRI }
    private void enablePeopleFiltering() {
        when(mSectionsFeatureManager.isFilteringEnabled()).thenReturn(true);
        when(mSectionsFeatureManager.getNumberOfBuckets()).thenReturn(4);
    }

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


    private void setStackState(ChildType... children) {
    private void setStackState(ChildType... children) {
        when(mNssl.getChildCount()).thenReturn(children.length);
        when(mNssl.getChildCount()).thenReturn(children.length);
        for (int i = 0; i < children.length; i++) {
        for (int i = 0; i < children.length; i++) {
            View child;
            View child;
            switch (children[i]) {
            switch (children[i]) {
                case HEADER:
                case PEOPLE_HEADER:
                    child = mSectionsManager.getPeopleHeaderView();
                    break;
                case ALERTING_HEADER:
                    child = mSectionsManager.getAlertingHeaderView();
                    break;
                case GENTLE_HEADER:
                    child = mSectionsManager.getGentleHeaderView();
                    child = mSectionsManager.getGentleHeaderView();
                    break;
                    break;
                case HIPRI:
                case HEADS_UP:
                case LOPRI:
                    child = mockNotification(BUCKET_HEADS_UP);
                    ExpandableNotificationRow notifRow = mock(ExpandableNotificationRow.class,
                    break;
                            RETURNS_DEEP_STUBS);
                case PERSON:
                    when(notifRow.getVisibility()).thenReturn(View.VISIBLE);
                    child = mockNotification(BUCKET_PEOPLE);
                    when(notifRow.getEntry().getBucket()).thenReturn(
                    break;
                            children[i] == ChildType.HIPRI ? BUCKET_ALERTING : BUCKET_SILENT);
                case ALERTING:
                    when(notifRow.getParent()).thenReturn(mNssl);
                    child = mockNotification(BUCKET_ALERTING);
                    child = notifRow;
                    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;
                    break;
                default:
                default:
                    throw new RuntimeException("Unknown ChildType: " + children[i]);
                    throw new RuntimeException("Unknown ChildType: " + children[i]);
@@ -289,4 +362,13 @@ public class NotificationSectionsManagerTest extends SysuiTestCase {
            when(mNssl.indexOfChild(child)).thenReturn(i);
            when(mNssl.indexOfChild(child)).thenReturn(i);
        }
        }
    }
    }

    private View mockNotification(int bucket) {
        ExpandableNotificationRow notifRow = mock(ExpandableNotificationRow.class,
                RETURNS_DEEP_STUBS);
        when(notifRow.getVisibility()).thenReturn(View.VISIBLE);
        when(notifRow.getEntry().getBucket()).thenReturn(bucket);
        when(notifRow.getParent()).thenReturn(mNssl);
        return notifRow;
    }
}
}