Merge "Notifications and quicksettings scroll independently in split shade" into sc-dev

This commit is contained in:
TreeHugger Robot
2021-02-22 11:26:22 +00:00
committed by Android (Google) Code Review
4 changed files with 115 additions and 27 deletions

View File

@@ -21,6 +21,7 @@ import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator
import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_SILENT; import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_SILENT;
import static com.android.systemui.statusbar.notification.stack.StackStateAnimator.ANIMATION_DURATION_SWIPE; import static com.android.systemui.statusbar.notification.stack.StackStateAnimator.ANIMATION_DURATION_SWIPE;
import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT; import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
import static com.android.systemui.util.Utils.shouldUseSplitNotificationShade;
import static java.lang.annotation.RetentionPolicy.SOURCE; import static java.lang.annotation.RetentionPolicy.SOURCE;
@@ -83,6 +84,7 @@ import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.DragDownHelper.DragDownCallback; import com.android.systemui.statusbar.DragDownHelper.DragDownCallback;
import com.android.systemui.statusbar.EmptyShadeView; import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationShelf; import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.NotificationShelfController; import com.android.systemui.statusbar.NotificationShelfController;
@@ -453,6 +455,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
private NotificationEntry mTopHeadsUpEntry; private NotificationEntry mTopHeadsUpEntry;
private long mNumHeadsUp; private long mNumHeadsUp;
private NotificationStackScrollLayoutController.TouchHandler mTouchHandler; private NotificationStackScrollLayoutController.TouchHandler mTouchHandler;
private final FeatureFlags mFeatureFlags;
private final ExpandableView.OnHeightChangedListener mOnChildHeightChangedListener = private final ExpandableView.OnHeightChangedListener mOnChildHeightChangedListener =
new ExpandableView.OnHeightChangedListener() { new ExpandableView.OnHeightChangedListener() {
@@ -492,8 +495,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
GroupMembershipManager groupMembershipManager, GroupMembershipManager groupMembershipManager,
GroupExpansionManager groupExpansionManager, GroupExpansionManager groupExpansionManager,
SysuiStatusBarStateController statusbarStateController, SysuiStatusBarStateController statusbarStateController,
AmbientState ambientState AmbientState ambientState,
) { FeatureFlags featureFlags) {
super(context, attrs, 0, 0); super(context, attrs, 0, 0);
Resources res = getResources(); Resources res = getResources();
mSectionsManager = notificationSectionsManager; mSectionsManager = notificationSectionsManager;
@@ -530,6 +533,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
mGroupMembershipManager = groupMembershipManager; mGroupMembershipManager = groupMembershipManager;
mGroupExpansionManager = groupExpansionManager; mGroupExpansionManager = groupExpansionManager;
mStatusbarStateController = statusbarStateController; mStatusbarStateController = statusbarStateController;
mFeatureFlags = featureFlags;
} }
void initializeForegroundServiceSection(ForegroundServiceDungeonView fgsSectionView) { void initializeForegroundServiceSection(ForegroundServiceDungeonView fgsSectionView) {
@@ -1156,8 +1160,13 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
if (stackStartPosition <= stackEndPosition) { if (stackStartPosition <= stackEndPosition) {
stackHeight = stackEndPosition; stackHeight = stackEndPosition;
} else { } else {
stackHeight = (int) NotificationUtils.interpolate(stackStartPosition, if (shouldUseSplitNotificationShade(mFeatureFlags, getResources())) {
stackEndPosition, mQsExpansionFraction); // This prevents notifications from being collapsed when QS is expanded.
stackHeight = (int) height;
} else {
stackHeight = (int) NotificationUtils.interpolate(stackStartPosition,
stackEndPosition, mQsExpansionFraction);
}
} }
} else { } else {
stackHeight = (int) height; stackHeight = (int) height;

View File

@@ -196,7 +196,8 @@ public class NotificationPanelViewController extends PanelViewController {
new MyOnHeadsUpChangedListener(); new MyOnHeadsUpChangedListener();
private final HeightListener mHeightListener = new HeightListener(); private final HeightListener mHeightListener = new HeightListener();
private final ConfigurationListener mConfigurationListener = new ConfigurationListener(); private final ConfigurationListener mConfigurationListener = new ConfigurationListener();
private final StatusBarStateListener mStatusBarStateListener = new StatusBarStateListener(); @VisibleForTesting final StatusBarStateListener mStatusBarStateListener =
new StatusBarStateListener();
private final ExpansionCallback mExpansionCallback = new ExpansionCallback(); private final ExpansionCallback mExpansionCallback = new ExpansionCallback();
private final BiometricUnlockController mBiometricUnlockController; private final BiometricUnlockController mBiometricUnlockController;
private final NotificationPanelView mView; private final NotificationPanelView mView;
@@ -1852,7 +1853,7 @@ public class NotificationPanelViewController extends PanelViewController {
} }
} }
private void setQsExpanded(boolean expanded) { @VisibleForTesting void setQsExpanded(boolean expanded) {
boolean changed = mQsExpanded != expanded; boolean changed = mQsExpanded != expanded;
if (changed) { if (changed) {
mQsExpanded = expanded; mQsExpanded = expanded;
@@ -1955,8 +1956,10 @@ public class NotificationPanelViewController extends PanelViewController {
private void updateQsState() { private void updateQsState() {
mNotificationStackScrollLayoutController.setQsExpanded(mQsExpanded); mNotificationStackScrollLayoutController.setQsExpanded(mQsExpanded);
mNotificationStackScrollLayoutController.setScrollingEnabled( mNotificationStackScrollLayoutController.setScrollingEnabled(
mBarState != KEYGUARD && (!mQsExpanded mBarState != KEYGUARD
|| mQsExpansionFromOverscroll)); && (!mQsExpanded
|| mQsExpansionFromOverscroll
|| Utils.shouldUseSplitNotificationShade(mFeatureFlags, mResources)));
if (mKeyguardUserSwitcherController != null && mQsExpanded if (mKeyguardUserSwitcherController != null && mQsExpanded
&& !mStackScrollerOverscrolling) { && !mStackScrollerOverscrolling) {
@@ -2236,13 +2239,16 @@ public class NotificationPanelViewController extends PanelViewController {
@Override @Override
protected boolean canCollapsePanelOnTouch() { protected boolean canCollapsePanelOnTouch() {
if (!isInSettings()) { if (!isInSettings() && mBarState == KEYGUARD) {
return mBarState == KEYGUARD
|| mIsPanelCollapseOnQQS
|| mNotificationStackScrollLayoutController.isScrolledToBottom();
} else {
return true; return true;
} }
if (mNotificationStackScrollLayoutController.isScrolledToBottom()) {
return true;
}
return !Utils.shouldUseSplitNotificationShade(mFeatureFlags, mResources)
&& (isInSettings() || mIsPanelCollapseOnQQS);
} }
@Override @Override
@@ -3615,6 +3621,10 @@ public class NotificationPanelViewController extends PanelViewController {
NotificationStackScrollLayout.OnOverscrollTopChangedListener { NotificationStackScrollLayout.OnOverscrollTopChangedListener {
@Override @Override
public void onOverscrollTopChanged(float amount, boolean isRubberbanded) { public void onOverscrollTopChanged(float amount, boolean isRubberbanded) {
// When in split shade, overscroll shouldn't carry through to QS
if (Utils.shouldUseSplitNotificationShade(mFeatureFlags, mResources)) {
return;
}
cancelQsAnimation(); cancelQsAnimation();
if (!mQsExpansionEnabled) { if (!mQsExpansionEnabled) {
amount = 0f; amount = 0f;

View File

@@ -21,6 +21,8 @@ import static android.provider.Settings.Secure.NOTIFICATION_HISTORY_ENABLED;
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_ALL; import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_ALL;
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_GENTLE; import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_GENTLE;
import static com.google.common.truth.Truth.assertWithMessage;
import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull; import static junit.framework.Assert.assertNotNull;
@@ -49,6 +51,7 @@ import com.android.systemui.ExpandHelper;
import com.android.systemui.R; import com.android.systemui.R;
import com.android.systemui.SysuiTestCase; import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.EmptyShadeView; import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationShelf; import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.NotificationShelfController; import com.android.systemui.statusbar.NotificationShelfController;
@@ -101,6 +104,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
@Mock private SysuiStatusBarStateController mStatusBarStateController; @Mock private SysuiStatusBarStateController mStatusBarStateController;
@Mock private NotificationSwipeHelper mNotificationSwipeHelper; @Mock private NotificationSwipeHelper mNotificationSwipeHelper;
@Mock private NotificationStackScrollLayoutController mStackScrollLayoutController; @Mock private NotificationStackScrollLayoutController mStackScrollLayoutController;
@Mock private FeatureFlags mFeatureFlags;
@Before @Before
@UiThreadTest @UiThreadTest
@@ -139,8 +143,8 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
mGroupMembershipManger, mGroupMembershipManger,
mGroupExpansionManager, mGroupExpansionManager,
mStatusBarStateController, mStatusBarStateController,
mAmbientState mAmbientState,
); mFeatureFlags);
mStackScrollerInternal.initView(getContext(), mKeyguardBypassEnabledProvider, mStackScrollerInternal.initView(getContext(), mKeyguardBypassEnabledProvider,
mNotificationSwipeHelper); mNotificationSwipeHelper);
mStackScroller = spy(mStackScrollerInternal); mStackScroller = spy(mStackScrollerInternal);
@@ -205,8 +209,8 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
@Test @Test
@UiThreadTest @UiThreadTest
public void testSetExpandedHeight_blockingHelperManagerReceivedCallbacks() { public void testSetExpandedHeight_blockingHelperManagerReceivedCallbacks() {
final float expectedHeight[] = {0f}; final float[] expectedHeight = {0f};
final float expectedAppear[] = {0f}; final float[] expectedAppear = {0f};
mStackScroller.addOnExpandedHeightChangedListener((height, appear) -> { mStackScroller.addOnExpandedHeightChangedListener((height, appear) -> {
Assert.assertEquals(expectedHeight[0], height, 0); Assert.assertEquals(expectedHeight[0], height, 0);
@@ -221,6 +225,29 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
mStackScroller.setExpandedHeight(expectedHeight[0]); mStackScroller.setExpandedHeight(expectedHeight[0]);
} }
@Test
@UiThreadTest
public void testSetExpandedHeight_withSplitShade_doesntInterpolateStackHeight() {
when(mFeatureFlags.isTwoColumnNotificationShadeEnabled()).thenReturn(true);
final int[] expectedStackHeight = {0};
mStackScroller.addOnExpandedHeightChangedListener((expandedHeight, appear) -> {
assertWithMessage("Given shade enabled: %s",
mFeatureFlags.isTwoColumnNotificationShadeEnabled())
.that(mStackScroller.getHeight())
.isEqualTo(expectedStackHeight[0]);
});
when(mFeatureFlags.isTwoColumnNotificationShadeEnabled()).thenReturn(false);
expectedStackHeight[0] = 0;
mStackScroller.setExpandedHeight(100f);
when(mFeatureFlags.isTwoColumnNotificationShadeEnabled()).thenReturn(true);
expectedStackHeight[0] = 100;
mStackScroller.setExpandedHeight(100f);
}
@Test @Test
public void manageNotifications_visible() { public void manageNotifications_visible() {
FooterView view = mock(FooterView.class); FooterView view = mock(FooterView.class);

View File

@@ -18,13 +18,15 @@ package com.android.systemui.statusbar.phone;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
import static com.android.systemui.statusbar.StatusBarState.SHADE;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy; import static org.mockito.Mockito.spy;
@@ -45,6 +47,7 @@ import android.view.LayoutInflater;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.ViewPropertyAnimator;
import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.AccessibilityNodeInfo;
@@ -53,6 +56,7 @@ import androidx.constraintlayout.widget.ConstraintSet;
import androidx.test.filters.SmallTest; import androidx.test.filters.SmallTest;
import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.testing.UiEventLoggerFake; import com.android.internal.logging.testing.UiEventLoggerFake;
import com.android.internal.util.LatencyTracker; import com.android.internal.util.LatencyTracker;
import com.android.keyguard.KeyguardClockSwitch; import com.android.keyguard.KeyguardClockSwitch;
@@ -100,7 +104,6 @@ import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
import org.mockito.InOrder;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
import org.mockito.stubbing.Answer; import org.mockito.stubbing.Answer;
@@ -116,8 +119,6 @@ public class NotificationPanelViewTest extends SysuiTestCase {
@Mock @Mock
private StatusBar mStatusBar; private StatusBar mStatusBar;
@Mock @Mock
private SysuiStatusBarStateController mStatusBarStateController;
@Mock
private NotificationStackScrollLayout mNotificationStackScrollLayout; private NotificationStackScrollLayout mNotificationStackScrollLayout;
@Mock @Mock
private KeyguardBottomAreaView mKeyguardBottomArea; private KeyguardBottomAreaView mKeyguardBottomArea;
@@ -227,7 +228,10 @@ public class NotificationPanelViewTest extends SysuiTestCase {
private AmbientState mAmbientState; private AmbientState mAmbientState;
@Mock @Mock
private UserManager mUserManager; private UserManager mUserManager;
@Mock
private UiEventLogger mUiEventLogger;
private SysuiStatusBarStateController mStatusBarStateController;
private NotificationPanelViewController mNotificationPanelViewController; private NotificationPanelViewController mNotificationPanelViewController;
private View.AccessibilityDelegate mAccessibiltyDelegate; private View.AccessibilityDelegate mAccessibiltyDelegate;
private NotificationsQuickSettingsContainer mNotificationContainerParent; private NotificationsQuickSettingsContainer mNotificationContainerParent;
@@ -235,6 +239,8 @@ public class NotificationPanelViewTest extends SysuiTestCase {
@Before @Before
public void setup() { public void setup() {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
mStatusBarStateController = new StatusBarStateControllerImpl(mUiEventLogger);
when(mAuthController.isUdfpsEnrolled(anyInt())).thenReturn(false); when(mAuthController.isUdfpsEnrolled(anyInt())).thenReturn(false);
when(mHeadsUpCallback.getContext()).thenReturn(mContext); when(mHeadsUpCallback.getContext()).thenReturn(mContext);
when(mView.getResources()).thenReturn(mResources); when(mView.getResources()).thenReturn(mResources);
@@ -258,6 +264,7 @@ public class NotificationPanelViewTest extends SysuiTestCase {
when(mView.findViewById(R.id.keyguard_bottom_area)).thenReturn(mKeyguardBottomArea); when(mView.findViewById(R.id.keyguard_bottom_area)).thenReturn(mKeyguardBottomArea);
when(mKeyguardBottomArea.getLeftView()).thenReturn(mock(KeyguardAffordanceView.class)); when(mKeyguardBottomArea.getLeftView()).thenReturn(mock(KeyguardAffordanceView.class));
when(mKeyguardBottomArea.getRightView()).thenReturn(mock(KeyguardAffordanceView.class)); when(mKeyguardBottomArea.getRightView()).thenReturn(mock(KeyguardAffordanceView.class));
when(mKeyguardBottomArea.animate()).thenReturn(mock(ViewPropertyAnimator.class));
when(mView.findViewById(R.id.big_clock_container)).thenReturn(mBigClockContainer); when(mView.findViewById(R.id.big_clock_container)).thenReturn(mBigClockContainer);
when(mView.findViewById(R.id.qs_frame)).thenReturn(mQsFrame); when(mView.findViewById(R.id.qs_frame)).thenReturn(mQsFrame);
when(mView.findViewById(R.id.keyguard_status_view)) when(mView.findViewById(R.id.keyguard_status_view))
@@ -336,17 +343,19 @@ public class NotificationPanelViewTest extends SysuiTestCase {
ArgumentCaptor.forClass(View.AccessibilityDelegate.class); ArgumentCaptor.forClass(View.AccessibilityDelegate.class);
verify(mView).setAccessibilityDelegate(accessibilityDelegateArgumentCaptor.capture()); verify(mView).setAccessibilityDelegate(accessibilityDelegateArgumentCaptor.capture());
mAccessibiltyDelegate = accessibilityDelegateArgumentCaptor.getValue(); mAccessibiltyDelegate = accessibilityDelegateArgumentCaptor.getValue();
mNotificationPanelViewController.mStatusBarStateController
.addCallback(mNotificationPanelViewController.mStatusBarStateListener);
mNotificationPanelViewController
.setHeadsUpAppearanceController(mock(HeadsUpAppearanceController.class));
} }
@Test @Test
public void testSetDozing_notifiesNsslAndStateController() { public void testSetDozing_notifiesNsslAndStateController() {
mNotificationPanelViewController.setDozing(true /* dozing */, true /* animate */, mNotificationPanelViewController.setDozing(true /* dozing */, false /* animate */,
null /* touch */); null /* touch */);
InOrder inOrder = inOrder( verify(mNotificationStackScrollLayoutController)
mNotificationStackScrollLayoutController, mStatusBarStateController); .setDozing(eq(true), eq(false), eq(null));
inOrder.verify(mNotificationStackScrollLayoutController) assertThat(mStatusBarStateController.getDozeAmount()).isEqualTo(1f);
.setDozing(eq(true), eq(true), eq(null));
inOrder.verify(mStatusBarStateController).setDozeAmount(eq(1f), eq(true));
} }
@Test @Test
@@ -489,6 +498,39 @@ public class NotificationPanelViewTest extends SysuiTestCase {
assertThat(stackScrollerLayout.startToStart).isEqualTo(R.id.qs_edge_guideline); assertThat(stackScrollerLayout.startToStart).isEqualTo(R.id.qs_edge_guideline);
} }
@Test
public void testCanCollapsePanelOnTouch_trueForKeyGuard() {
mStatusBarStateController.setState(KEYGUARD);
assertThat(mNotificationPanelViewController.canCollapsePanelOnTouch()).isTrue();
}
@Test
public void testCanCollapsePanelOnTouch_trueWhenScrolledToBottom() {
mStatusBarStateController.setState(SHADE);
when(mNotificationStackScrollLayoutController.isScrolledToBottom()).thenReturn(true);
assertThat(mNotificationPanelViewController.canCollapsePanelOnTouch()).isTrue();
}
@Test
public void testCanCollapsePanelOnTouch_trueWhenInSettings() {
mStatusBarStateController.setState(SHADE);
mNotificationPanelViewController.setQsExpanded(true);
assertThat(mNotificationPanelViewController.canCollapsePanelOnTouch()).isTrue();
}
@Test
public void testCanCollapsePanelOnTouch_falseInDualPaneShade() {
mStatusBarStateController.setState(SHADE);
when(mResources.getBoolean(R.bool.config_use_split_notification_shade)).thenReturn(true);
when(mFeatureFlags.isTwoColumnNotificationShadeEnabled()).thenReturn(true);
mNotificationPanelViewController.setQsExpanded(true);
assertThat(mNotificationPanelViewController.canCollapsePanelOnTouch()).isFalse();
}
private View newViewWithId(int id) { private View newViewWithId(int id) {
View view = new View(mContext); View view = new View(mContext);
view.setId(id); view.setId(id);