Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +42 −69 Original line number Diff line number Diff line Loading @@ -185,6 +185,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable * gap is drawn between them). In this case we don't want to round their corners. */ private static final int DISTANCE_BETWEEN_ADJACENT_SECTIONS_PX = 1; private OnMenuEventListener mMenuEventListener; private KeyguardBypassEnabledProvider mKeyguardBypassEnabledProvider; private final DynamicPrivacyController mDynamicPrivacyController; private final SysuiStatusBarStateController mStatusbarStateController; Loading Loading @@ -316,7 +317,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable * motion. */ private int mMaxScrollAfterExpand; private ExpandableNotificationRow.LongPressListener mLongPressListener; boolean mCheckForLeavebehind; /** Loading Loading @@ -608,8 +608,27 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable minHeight, maxHeight); mExpandHelper.setEventSource(this); mExpandHelper.setScrollAdapter(mScrollAdapter); // TODO: move swipe helper into controller. // The anonymous proxy through to mMenuEventListener is temporary until more can be moved // into the controller. mSwipeHelper = new NotificationSwipeHelper(SwipeHelper.X, mNotificationCallback, getContext(), mMenuEventListener, mFalsingManager); getContext(), new OnMenuEventListener() { @Override public void onMenuClicked(View row, int x, int y, MenuItem menu) { mMenuEventListener.onMenuClicked(row, x, y, menu); } @Override public void onMenuReset(View row) { mMenuEventListener.onMenuReset(row); } @Override public void onMenuShown(View row) { mMenuEventListener.onMenuShown(row); } }, mFalsingManager); mStackScrollAlgorithm = createStackScrollAlgorithm(context); mShouldDrawNotificationBackground = res.getBoolean(R.bool.config_drawNotificationBackground); Loading Loading @@ -3753,11 +3772,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable return y < getHeight() - getEmptyBottomMargin(); } @ShadeViewRefactor(RefactorComponent.INPUT) public void setLongPressListener(ExpandableNotificationRow.LongPressListener listener) { mLongPressListener = listener; } private float getTouchSlop(MotionEvent event) { // Adjust the touch slop if another gesture may be being performed. return event.getClassification() == MotionEvent.CLASSIFICATION_AMBIGUOUS_GESTURE Loading Loading @@ -5812,6 +5826,27 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable mCurrentUserId = userId; } void onMenuShown(View row) { mSwipeHelper.onMenuShown(row); } void onMenuReset(View row) { View translatingParentView = mSwipeHelper.getTranslatingParentView(); if (translatingParentView != null && row == translatingParentView) { mSwipeHelper.clearExposedMenuView(); mSwipeHelper.clearTranslatingParentView(); if (row instanceof ExpandableNotificationRow) { mHeadsUpManager.setMenuShown( ((ExpandableNotificationRow) row).getEntry(), false); } } } void setMenuEventListener(OnMenuEventListener menuEventListener) { mMenuEventListener = menuEventListener; } /** * A listener that is notified when the empty space below the notifications is clicked on */ Loading Loading @@ -6167,69 +6202,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable } } @VisibleForTesting @ShadeViewRefactor(RefactorComponent.INPUT) protected final OnMenuEventListener mMenuEventListener = new OnMenuEventListener() { @Override public void onMenuClicked(View view, int x, int y, MenuItem item) { if (mLongPressListener == null) { return; } if (view instanceof ExpandableNotificationRow) { ExpandableNotificationRow row = (ExpandableNotificationRow) view; mMetricsLogger.write(row.getEntry().getSbn().getLogMaker() .setCategory(MetricsEvent.ACTION_TOUCH_GEAR) .setType(MetricsEvent.TYPE_ACTION) ); } mLongPressListener.onLongPress(view, x, y, item); } @Override public void onMenuReset(View row) { View translatingParentView = mSwipeHelper.getTranslatingParentView(); if (translatingParentView != null && row == translatingParentView) { mSwipeHelper.clearExposedMenuView(); mSwipeHelper.clearTranslatingParentView(); if (row instanceof ExpandableNotificationRow) { mHeadsUpManager.setMenuShown( ((ExpandableNotificationRow) row).getEntry(), false); } } } @Override public void onMenuShown(View row) { if (row instanceof ExpandableNotificationRow) { ExpandableNotificationRow notificationRow = (ExpandableNotificationRow) row; mMetricsLogger.write(notificationRow.getEntry().getSbn().getLogMaker() .setCategory(MetricsEvent.ACTION_REVEAL_GEAR) .setType(MetricsEvent.TYPE_ACTION)); mHeadsUpManager.setMenuShown(notificationRow.getEntry(), true); mSwipeHelper.onMenuShown(row); mNotificationGutsManager.closeAndSaveGuts(true /* removeLeavebehind */, false /* force */, false /* removeControls */, -1 /* x */, -1 /* y */, false /* resetMenu */); // Check to see if we want to go directly to the notfication guts NotificationMenuRowPlugin provider = notificationRow.getProvider(); if (provider.shouldShowGutsOnSnapOpen()) { MenuItem item = provider.menuItemToExposeOnSnap(); if (item != null) { Point origin = provider.getRevealAnimationOrigin(); mNotificationGutsManager.openGuts(row, origin.x, origin.y, item); } else { Log.e(TAG, "Provider has shouldShowGutsOnSnapOpen, but provided no " + "menu item in menuItemtoExposeOnSnap. Skipping."); } // Close the menu row since we went directly to the guts resetExposedMenuView(false, true); } } } }; @ShadeViewRefactor(RefactorComponent.INPUT) private final NotificationSwipeHelper.NotificationCallback mNotificationCallback = Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java +68 −5 Original line number Diff line number Diff line Loading @@ -18,8 +18,10 @@ package com.android.systemui.statusbar.notification.stack; import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME; import android.graphics.Point; import android.graphics.PointF; import android.provider.Settings; import android.util.Log; import android.view.Display; import android.view.View; import android.view.ViewGroup; Loading @@ -27,8 +29,12 @@ import android.view.WindowInsets; import android.widget.FrameLayout; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.media.KeyguardMediaController; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.OnMenuEventListener; import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.NotificationLockscreenUserManager; Loading Loading @@ -72,6 +78,8 @@ import kotlin.Unit; */ @StatusBarComponent.StatusBarScope public class NotificationStackScrollLayoutController { private static final String TAG = "StackScrollerController"; private final boolean mAllowLongPress; private final NotificationGutsManager mNotificationGutsManager; private final HeadsUpManagerPhone mHeadsUpManager; Loading @@ -80,6 +88,7 @@ public class NotificationStackScrollLayoutController { private final DynamicPrivacyController mDynamicPrivacyController; private final ConfigurationController mConfigurationController; private final ZenModeController mZenModeController; private final MetricsLogger mMetricsLogger; private final KeyguardMediaController mKeyguardMediaController; private final SysuiStatusBarStateController mStatusBarStateController; private final KeyguardBypassController mKeyguardBypassController; Loading Loading @@ -175,6 +184,60 @@ public class NotificationStackScrollLayoutController { } }; private final OnMenuEventListener mMenuEventListener = new OnMenuEventListener() { @Override public void onMenuClicked( View view, int x, int y, NotificationMenuRowPlugin.MenuItem item) { if (!mAllowLongPress) { return; } if (view instanceof ExpandableNotificationRow) { ExpandableNotificationRow row = (ExpandableNotificationRow) view; mMetricsLogger.write(row.getEntry().getSbn().getLogMaker() .setCategory(MetricsEvent.ACTION_TOUCH_GEAR) .setType(MetricsEvent.TYPE_ACTION) ); } mNotificationGutsManager.openGuts(view, x, y, item); } @Override public void onMenuReset(View row) { mView.onMenuReset(row); } @Override public void onMenuShown(View row) { if (row instanceof ExpandableNotificationRow) { ExpandableNotificationRow notificationRow = (ExpandableNotificationRow) row; mMetricsLogger.write(notificationRow.getEntry().getSbn().getLogMaker() .setCategory(MetricsEvent.ACTION_REVEAL_GEAR) .setType(MetricsEvent.TYPE_ACTION)); mHeadsUpManager.setMenuShown(notificationRow.getEntry(), true); mView.onMenuShown(row); mNotificationGutsManager.closeAndSaveGuts(true /* removeLeavebehind */, false /* force */, false /* removeControls */, -1 /* x */, -1 /* y */, false /* resetMenu */); // Check to see if we want to go directly to the notification guts NotificationMenuRowPlugin provider = notificationRow.getProvider(); if (provider.shouldShowGutsOnSnapOpen()) { NotificationMenuRowPlugin.MenuItem item = provider.menuItemToExposeOnSnap(); if (item != null) { Point origin = provider.getRevealAnimationOrigin(); mNotificationGutsManager.openGuts(row, origin.x, origin.y, item); } else { Log.e(TAG, "Provider has shouldShowGutsOnSnapOpen, but provided no " + "menu item in menuItemtoExposeOnSnap. Skipping."); } // Close the menu row since we went directly to the guts mView.resetExposedMenuView(false, true); } } } }; @Inject public NotificationStackScrollLayoutController( @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowLongPress, Loading @@ -189,7 +252,8 @@ public class NotificationStackScrollLayoutController { KeyguardBypassController keyguardBypassController, ZenModeController zenModeController, SysuiColorExtractor colorExtractor, NotificationLockscreenUserManager lockscreenUserManager) { NotificationLockscreenUserManager lockscreenUserManager, MetricsLogger metricsLogger) { mAllowLongPress = allowLongPress; mNotificationGutsManager = notificationGutsManager; mHeadsUpManager = headsUpManager; Loading @@ -203,6 +267,7 @@ public class NotificationStackScrollLayoutController { mZenModeController = zenModeController; mColorExtractor = colorExtractor; mLockscreenUserManager = lockscreenUserManager; mMetricsLogger = metricsLogger; } public void attach(NotificationStackScrollLayout view) { Loading @@ -210,16 +275,14 @@ public class NotificationStackScrollLayoutController { mView.setController(this); mView.initView(mView.getContext(), mKeyguardBypassController::getBypassEnabled); if (mAllowLongPress) { mView.setLongPressListener(mNotificationGutsManager::openGuts); } mHeadsUpManager.addListener(mNotificationRoundnessManager); // TODO: why is this here? mDynamicPrivacyController.addListener(mDynamicPrivacyControllerListener); mLockscreenUserManager.addUserChangedListener(mLockscreenUserChangeListener); mView.setCurrentUserid(mLockscreenUserManager.getCurrentUserId()); mView.setMenuEventListener(mMenuEventListener); mNotificationRoundnessManager.setOnRoundingChangedCallback(mView::invalidate); mView.addOnExpandedHeightChangedListener(mNotificationRoundnessManager::setExpanded); Loading packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java +0 −59 Original line number Diff line number Diff line Loading @@ -24,9 +24,7 @@ import static org.junit.Assert.assertFalse; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.RETURNS_DEEP_STUBS; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doNothing; Loading @@ -47,7 +45,6 @@ import androidx.test.annotation.UiThreadTest; import androidx.test.filters.SmallTest; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto; import com.android.internal.logging.testing.UiEventLoggerFake; import com.android.internal.statusbar.IStatusBarService; import com.android.systemui.ExpandHelper; Loading Loading @@ -99,7 +96,6 @@ import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.ArgumentMatcher; import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; Loading Loading @@ -451,61 +447,6 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { assertNull(swipeActionHelper.getExposedMenuView()); } class LogMatcher implements ArgumentMatcher<LogMaker> { private int mCategory, mType; LogMatcher(int category, int type) { mCategory = category; mType = type; } public boolean matches(LogMaker l) { return (l.getCategory() == mCategory) && (l.getType() == mType); } public String toString() { return String.format("LogMaker(%d, %d)", mCategory, mType); } } private LogMaker logMatcher(int category, int type) { return argThat(new LogMatcher(category, type)); } @Test @UiThreadTest public void testOnMenuClickedLogging() { // Set up the object under test to have a valid mLongPressListener. We're testing an // anonymous-class member, mMenuEventListener, so we need to modify the state of the // class itself, not the Mockito spy copied from it. See notes in setup. mStackScrollerInternal.setLongPressListener( mock(ExpandableNotificationRow.LongPressListener.class)); ExpandableNotificationRow row = mock(ExpandableNotificationRow.class, RETURNS_DEEP_STUBS); when(row.getEntry().getSbn().getLogMaker()).thenReturn(new LogMaker( MetricsProto.MetricsEvent.VIEW_UNKNOWN)); mStackScroller.mMenuEventListener.onMenuClicked(row, 0, 0, mock( NotificationMenuRowPlugin.MenuItem.class)); verify(row.getEntry().getSbn()).getLogMaker(); // This writes most of the log data verify(mMetricsLogger).write(logMatcher(MetricsProto.MetricsEvent.ACTION_TOUCH_GEAR, MetricsProto.MetricsEvent.TYPE_ACTION)); } @Test @UiThreadTest public void testOnMenuShownLogging() { ; ExpandableNotificationRow row = mock(ExpandableNotificationRow.class, RETURNS_DEEP_STUBS); when(row.getEntry().getSbn().getLogMaker()).thenReturn(new LogMaker( MetricsProto.MetricsEvent.VIEW_UNKNOWN)); mStackScroller.mMenuEventListener.onMenuShown(row); verify(row.getEntry().getSbn()).getLogMaker(); // This writes most of the log data verify(mMetricsLogger).write(logMatcher(MetricsProto.MetricsEvent.ACTION_REVEAL_GEAR, MetricsProto.MetricsEvent.TYPE_ACTION)); } @Test public void testClearNotifications_All() { mStackScroller.clearNotifications(NotificationStackScrollLayout.ROWS_ALL, true); Loading packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java +84 −2 Original line number Diff line number Diff line Loading @@ -18,23 +18,32 @@ package com.android.systemui.statusbar.notification.stack; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Mockito.RETURNS_DEEP_STUBS; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.metrics.LogMaker; import android.testing.AndroidTestingRunner; import androidx.test.filters.SmallTest; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto; import com.android.systemui.SysuiTestCase; import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.media.KeyguardMediaController; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.OnMenuEventListener; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.notification.DynamicPrivacyController; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.phone.HeadsUpManagerPhone; import com.android.systemui.statusbar.phone.KeyguardBypassController; Loading @@ -46,6 +55,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.ArgumentMatcher; import org.mockito.Mock; import org.mockito.MockitoAnnotations; Loading Loading @@ -82,8 +92,10 @@ public class NotificationStackScrollerControllerTest extends SysuiTestCase { private SysuiColorExtractor mColorExtractor; @Mock private NotificationLockscreenUserManager mNotificationLockscreenUserManager; @Mock private MetricsLogger mMetricsLogger; NotificationStackScrollLayoutController mController; private NotificationStackScrollLayoutController mController; @Before public void setUp() { Loading @@ -102,7 +114,9 @@ public class NotificationStackScrollerControllerTest extends SysuiTestCase { mKeyguardBypassController, mZenModeController, mColorExtractor, mNotificationLockscreenUserManager); mNotificationLockscreenUserManager, mMetricsLogger ); when(mNotificationStackScrollLayout.isAttachedToWindow()).thenReturn(true); } Loading Loading @@ -205,4 +219,72 @@ public class NotificationStackScrollerControllerTest extends SysuiTestCase { stateListener.onStatePostChange(); verify(mNotificationStackScrollLayout).updateSensitiveness(false, true); } @Test public void testOnMenuShownLogging() { ; ExpandableNotificationRow row = mock(ExpandableNotificationRow.class, RETURNS_DEEP_STUBS); when(row.getEntry().getSbn().getLogMaker()).thenReturn(new LogMaker( MetricsProto.MetricsEvent.VIEW_UNKNOWN)); ArgumentCaptor<OnMenuEventListener> onMenuEventListenerArgumentCaptor = ArgumentCaptor.forClass(OnMenuEventListener.class); mController.attach(mNotificationStackScrollLayout); verify(mNotificationStackScrollLayout).setMenuEventListener( onMenuEventListenerArgumentCaptor.capture()); OnMenuEventListener onMenuEventListener = onMenuEventListenerArgumentCaptor.getValue(); onMenuEventListener.onMenuShown(row); verify(row.getEntry().getSbn()).getLogMaker(); // This writes most of the log data verify(mMetricsLogger).write(logMatcher(MetricsProto.MetricsEvent.ACTION_REVEAL_GEAR, MetricsProto.MetricsEvent.TYPE_ACTION)); } @Test public void testOnMenuClickedLogging() { ExpandableNotificationRow row = mock(ExpandableNotificationRow.class, RETURNS_DEEP_STUBS); when(row.getEntry().getSbn().getLogMaker()).thenReturn(new LogMaker( MetricsProto.MetricsEvent.VIEW_UNKNOWN)); ArgumentCaptor<OnMenuEventListener> onMenuEventListenerArgumentCaptor = ArgumentCaptor.forClass(OnMenuEventListener.class); mController.attach(mNotificationStackScrollLayout); verify(mNotificationStackScrollLayout).setMenuEventListener( onMenuEventListenerArgumentCaptor.capture()); OnMenuEventListener onMenuEventListener = onMenuEventListenerArgumentCaptor.getValue(); onMenuEventListener.onMenuClicked(row, 0, 0, mock( NotificationMenuRowPlugin.MenuItem.class)); verify(row.getEntry().getSbn()).getLogMaker(); // This writes most of the log data verify(mMetricsLogger).write(logMatcher(MetricsProto.MetricsEvent.ACTION_TOUCH_GEAR, MetricsProto.MetricsEvent.TYPE_ACTION)); } private LogMaker logMatcher(int category, int type) { return argThat(new LogMatcher(category, type)); } static class LogMatcher implements ArgumentMatcher<LogMaker> { private int mCategory, mType; LogMatcher(int category, int type) { mCategory = category; mType = type; } public boolean matches(LogMaker l) { return (l.getCategory() == mCategory) && (l.getType() == mType); } public String toString() { return String.format("LogMaker(%d, %d)", mCategory, mType); } } } Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +42 −69 Original line number Diff line number Diff line Loading @@ -185,6 +185,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable * gap is drawn between them). In this case we don't want to round their corners. */ private static final int DISTANCE_BETWEEN_ADJACENT_SECTIONS_PX = 1; private OnMenuEventListener mMenuEventListener; private KeyguardBypassEnabledProvider mKeyguardBypassEnabledProvider; private final DynamicPrivacyController mDynamicPrivacyController; private final SysuiStatusBarStateController mStatusbarStateController; Loading Loading @@ -316,7 +317,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable * motion. */ private int mMaxScrollAfterExpand; private ExpandableNotificationRow.LongPressListener mLongPressListener; boolean mCheckForLeavebehind; /** Loading Loading @@ -608,8 +608,27 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable minHeight, maxHeight); mExpandHelper.setEventSource(this); mExpandHelper.setScrollAdapter(mScrollAdapter); // TODO: move swipe helper into controller. // The anonymous proxy through to mMenuEventListener is temporary until more can be moved // into the controller. mSwipeHelper = new NotificationSwipeHelper(SwipeHelper.X, mNotificationCallback, getContext(), mMenuEventListener, mFalsingManager); getContext(), new OnMenuEventListener() { @Override public void onMenuClicked(View row, int x, int y, MenuItem menu) { mMenuEventListener.onMenuClicked(row, x, y, menu); } @Override public void onMenuReset(View row) { mMenuEventListener.onMenuReset(row); } @Override public void onMenuShown(View row) { mMenuEventListener.onMenuShown(row); } }, mFalsingManager); mStackScrollAlgorithm = createStackScrollAlgorithm(context); mShouldDrawNotificationBackground = res.getBoolean(R.bool.config_drawNotificationBackground); Loading Loading @@ -3753,11 +3772,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable return y < getHeight() - getEmptyBottomMargin(); } @ShadeViewRefactor(RefactorComponent.INPUT) public void setLongPressListener(ExpandableNotificationRow.LongPressListener listener) { mLongPressListener = listener; } private float getTouchSlop(MotionEvent event) { // Adjust the touch slop if another gesture may be being performed. return event.getClassification() == MotionEvent.CLASSIFICATION_AMBIGUOUS_GESTURE Loading Loading @@ -5812,6 +5826,27 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable mCurrentUserId = userId; } void onMenuShown(View row) { mSwipeHelper.onMenuShown(row); } void onMenuReset(View row) { View translatingParentView = mSwipeHelper.getTranslatingParentView(); if (translatingParentView != null && row == translatingParentView) { mSwipeHelper.clearExposedMenuView(); mSwipeHelper.clearTranslatingParentView(); if (row instanceof ExpandableNotificationRow) { mHeadsUpManager.setMenuShown( ((ExpandableNotificationRow) row).getEntry(), false); } } } void setMenuEventListener(OnMenuEventListener menuEventListener) { mMenuEventListener = menuEventListener; } /** * A listener that is notified when the empty space below the notifications is clicked on */ Loading Loading @@ -6167,69 +6202,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable } } @VisibleForTesting @ShadeViewRefactor(RefactorComponent.INPUT) protected final OnMenuEventListener mMenuEventListener = new OnMenuEventListener() { @Override public void onMenuClicked(View view, int x, int y, MenuItem item) { if (mLongPressListener == null) { return; } if (view instanceof ExpandableNotificationRow) { ExpandableNotificationRow row = (ExpandableNotificationRow) view; mMetricsLogger.write(row.getEntry().getSbn().getLogMaker() .setCategory(MetricsEvent.ACTION_TOUCH_GEAR) .setType(MetricsEvent.TYPE_ACTION) ); } mLongPressListener.onLongPress(view, x, y, item); } @Override public void onMenuReset(View row) { View translatingParentView = mSwipeHelper.getTranslatingParentView(); if (translatingParentView != null && row == translatingParentView) { mSwipeHelper.clearExposedMenuView(); mSwipeHelper.clearTranslatingParentView(); if (row instanceof ExpandableNotificationRow) { mHeadsUpManager.setMenuShown( ((ExpandableNotificationRow) row).getEntry(), false); } } } @Override public void onMenuShown(View row) { if (row instanceof ExpandableNotificationRow) { ExpandableNotificationRow notificationRow = (ExpandableNotificationRow) row; mMetricsLogger.write(notificationRow.getEntry().getSbn().getLogMaker() .setCategory(MetricsEvent.ACTION_REVEAL_GEAR) .setType(MetricsEvent.TYPE_ACTION)); mHeadsUpManager.setMenuShown(notificationRow.getEntry(), true); mSwipeHelper.onMenuShown(row); mNotificationGutsManager.closeAndSaveGuts(true /* removeLeavebehind */, false /* force */, false /* removeControls */, -1 /* x */, -1 /* y */, false /* resetMenu */); // Check to see if we want to go directly to the notfication guts NotificationMenuRowPlugin provider = notificationRow.getProvider(); if (provider.shouldShowGutsOnSnapOpen()) { MenuItem item = provider.menuItemToExposeOnSnap(); if (item != null) { Point origin = provider.getRevealAnimationOrigin(); mNotificationGutsManager.openGuts(row, origin.x, origin.y, item); } else { Log.e(TAG, "Provider has shouldShowGutsOnSnapOpen, but provided no " + "menu item in menuItemtoExposeOnSnap. Skipping."); } // Close the menu row since we went directly to the guts resetExposedMenuView(false, true); } } } }; @ShadeViewRefactor(RefactorComponent.INPUT) private final NotificationSwipeHelper.NotificationCallback mNotificationCallback = Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java +68 −5 Original line number Diff line number Diff line Loading @@ -18,8 +18,10 @@ package com.android.systemui.statusbar.notification.stack; import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME; import android.graphics.Point; import android.graphics.PointF; import android.provider.Settings; import android.util.Log; import android.view.Display; import android.view.View; import android.view.ViewGroup; Loading @@ -27,8 +29,12 @@ import android.view.WindowInsets; import android.widget.FrameLayout; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.media.KeyguardMediaController; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.OnMenuEventListener; import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.NotificationLockscreenUserManager; Loading Loading @@ -72,6 +78,8 @@ import kotlin.Unit; */ @StatusBarComponent.StatusBarScope public class NotificationStackScrollLayoutController { private static final String TAG = "StackScrollerController"; private final boolean mAllowLongPress; private final NotificationGutsManager mNotificationGutsManager; private final HeadsUpManagerPhone mHeadsUpManager; Loading @@ -80,6 +88,7 @@ public class NotificationStackScrollLayoutController { private final DynamicPrivacyController mDynamicPrivacyController; private final ConfigurationController mConfigurationController; private final ZenModeController mZenModeController; private final MetricsLogger mMetricsLogger; private final KeyguardMediaController mKeyguardMediaController; private final SysuiStatusBarStateController mStatusBarStateController; private final KeyguardBypassController mKeyguardBypassController; Loading Loading @@ -175,6 +184,60 @@ public class NotificationStackScrollLayoutController { } }; private final OnMenuEventListener mMenuEventListener = new OnMenuEventListener() { @Override public void onMenuClicked( View view, int x, int y, NotificationMenuRowPlugin.MenuItem item) { if (!mAllowLongPress) { return; } if (view instanceof ExpandableNotificationRow) { ExpandableNotificationRow row = (ExpandableNotificationRow) view; mMetricsLogger.write(row.getEntry().getSbn().getLogMaker() .setCategory(MetricsEvent.ACTION_TOUCH_GEAR) .setType(MetricsEvent.TYPE_ACTION) ); } mNotificationGutsManager.openGuts(view, x, y, item); } @Override public void onMenuReset(View row) { mView.onMenuReset(row); } @Override public void onMenuShown(View row) { if (row instanceof ExpandableNotificationRow) { ExpandableNotificationRow notificationRow = (ExpandableNotificationRow) row; mMetricsLogger.write(notificationRow.getEntry().getSbn().getLogMaker() .setCategory(MetricsEvent.ACTION_REVEAL_GEAR) .setType(MetricsEvent.TYPE_ACTION)); mHeadsUpManager.setMenuShown(notificationRow.getEntry(), true); mView.onMenuShown(row); mNotificationGutsManager.closeAndSaveGuts(true /* removeLeavebehind */, false /* force */, false /* removeControls */, -1 /* x */, -1 /* y */, false /* resetMenu */); // Check to see if we want to go directly to the notification guts NotificationMenuRowPlugin provider = notificationRow.getProvider(); if (provider.shouldShowGutsOnSnapOpen()) { NotificationMenuRowPlugin.MenuItem item = provider.menuItemToExposeOnSnap(); if (item != null) { Point origin = provider.getRevealAnimationOrigin(); mNotificationGutsManager.openGuts(row, origin.x, origin.y, item); } else { Log.e(TAG, "Provider has shouldShowGutsOnSnapOpen, but provided no " + "menu item in menuItemtoExposeOnSnap. Skipping."); } // Close the menu row since we went directly to the guts mView.resetExposedMenuView(false, true); } } } }; @Inject public NotificationStackScrollLayoutController( @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowLongPress, Loading @@ -189,7 +252,8 @@ public class NotificationStackScrollLayoutController { KeyguardBypassController keyguardBypassController, ZenModeController zenModeController, SysuiColorExtractor colorExtractor, NotificationLockscreenUserManager lockscreenUserManager) { NotificationLockscreenUserManager lockscreenUserManager, MetricsLogger metricsLogger) { mAllowLongPress = allowLongPress; mNotificationGutsManager = notificationGutsManager; mHeadsUpManager = headsUpManager; Loading @@ -203,6 +267,7 @@ public class NotificationStackScrollLayoutController { mZenModeController = zenModeController; mColorExtractor = colorExtractor; mLockscreenUserManager = lockscreenUserManager; mMetricsLogger = metricsLogger; } public void attach(NotificationStackScrollLayout view) { Loading @@ -210,16 +275,14 @@ public class NotificationStackScrollLayoutController { mView.setController(this); mView.initView(mView.getContext(), mKeyguardBypassController::getBypassEnabled); if (mAllowLongPress) { mView.setLongPressListener(mNotificationGutsManager::openGuts); } mHeadsUpManager.addListener(mNotificationRoundnessManager); // TODO: why is this here? mDynamicPrivacyController.addListener(mDynamicPrivacyControllerListener); mLockscreenUserManager.addUserChangedListener(mLockscreenUserChangeListener); mView.setCurrentUserid(mLockscreenUserManager.getCurrentUserId()); mView.setMenuEventListener(mMenuEventListener); mNotificationRoundnessManager.setOnRoundingChangedCallback(mView::invalidate); mView.addOnExpandedHeightChangedListener(mNotificationRoundnessManager::setExpanded); Loading
packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java +0 −59 Original line number Diff line number Diff line Loading @@ -24,9 +24,7 @@ import static org.junit.Assert.assertFalse; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.RETURNS_DEEP_STUBS; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doNothing; Loading @@ -47,7 +45,6 @@ import androidx.test.annotation.UiThreadTest; import androidx.test.filters.SmallTest; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto; import com.android.internal.logging.testing.UiEventLoggerFake; import com.android.internal.statusbar.IStatusBarService; import com.android.systemui.ExpandHelper; Loading Loading @@ -99,7 +96,6 @@ import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.ArgumentMatcher; import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; Loading Loading @@ -451,61 +447,6 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { assertNull(swipeActionHelper.getExposedMenuView()); } class LogMatcher implements ArgumentMatcher<LogMaker> { private int mCategory, mType; LogMatcher(int category, int type) { mCategory = category; mType = type; } public boolean matches(LogMaker l) { return (l.getCategory() == mCategory) && (l.getType() == mType); } public String toString() { return String.format("LogMaker(%d, %d)", mCategory, mType); } } private LogMaker logMatcher(int category, int type) { return argThat(new LogMatcher(category, type)); } @Test @UiThreadTest public void testOnMenuClickedLogging() { // Set up the object under test to have a valid mLongPressListener. We're testing an // anonymous-class member, mMenuEventListener, so we need to modify the state of the // class itself, not the Mockito spy copied from it. See notes in setup. mStackScrollerInternal.setLongPressListener( mock(ExpandableNotificationRow.LongPressListener.class)); ExpandableNotificationRow row = mock(ExpandableNotificationRow.class, RETURNS_DEEP_STUBS); when(row.getEntry().getSbn().getLogMaker()).thenReturn(new LogMaker( MetricsProto.MetricsEvent.VIEW_UNKNOWN)); mStackScroller.mMenuEventListener.onMenuClicked(row, 0, 0, mock( NotificationMenuRowPlugin.MenuItem.class)); verify(row.getEntry().getSbn()).getLogMaker(); // This writes most of the log data verify(mMetricsLogger).write(logMatcher(MetricsProto.MetricsEvent.ACTION_TOUCH_GEAR, MetricsProto.MetricsEvent.TYPE_ACTION)); } @Test @UiThreadTest public void testOnMenuShownLogging() { ; ExpandableNotificationRow row = mock(ExpandableNotificationRow.class, RETURNS_DEEP_STUBS); when(row.getEntry().getSbn().getLogMaker()).thenReturn(new LogMaker( MetricsProto.MetricsEvent.VIEW_UNKNOWN)); mStackScroller.mMenuEventListener.onMenuShown(row); verify(row.getEntry().getSbn()).getLogMaker(); // This writes most of the log data verify(mMetricsLogger).write(logMatcher(MetricsProto.MetricsEvent.ACTION_REVEAL_GEAR, MetricsProto.MetricsEvent.TYPE_ACTION)); } @Test public void testClearNotifications_All() { mStackScroller.clearNotifications(NotificationStackScrollLayout.ROWS_ALL, true); Loading
packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java +84 −2 Original line number Diff line number Diff line Loading @@ -18,23 +18,32 @@ package com.android.systemui.statusbar.notification.stack; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Mockito.RETURNS_DEEP_STUBS; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.metrics.LogMaker; import android.testing.AndroidTestingRunner; import androidx.test.filters.SmallTest; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto; import com.android.systemui.SysuiTestCase; import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.media.KeyguardMediaController; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.OnMenuEventListener; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.notification.DynamicPrivacyController; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.phone.HeadsUpManagerPhone; import com.android.systemui.statusbar.phone.KeyguardBypassController; Loading @@ -46,6 +55,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.ArgumentMatcher; import org.mockito.Mock; import org.mockito.MockitoAnnotations; Loading Loading @@ -82,8 +92,10 @@ public class NotificationStackScrollerControllerTest extends SysuiTestCase { private SysuiColorExtractor mColorExtractor; @Mock private NotificationLockscreenUserManager mNotificationLockscreenUserManager; @Mock private MetricsLogger mMetricsLogger; NotificationStackScrollLayoutController mController; private NotificationStackScrollLayoutController mController; @Before public void setUp() { Loading @@ -102,7 +114,9 @@ public class NotificationStackScrollerControllerTest extends SysuiTestCase { mKeyguardBypassController, mZenModeController, mColorExtractor, mNotificationLockscreenUserManager); mNotificationLockscreenUserManager, mMetricsLogger ); when(mNotificationStackScrollLayout.isAttachedToWindow()).thenReturn(true); } Loading Loading @@ -205,4 +219,72 @@ public class NotificationStackScrollerControllerTest extends SysuiTestCase { stateListener.onStatePostChange(); verify(mNotificationStackScrollLayout).updateSensitiveness(false, true); } @Test public void testOnMenuShownLogging() { ; ExpandableNotificationRow row = mock(ExpandableNotificationRow.class, RETURNS_DEEP_STUBS); when(row.getEntry().getSbn().getLogMaker()).thenReturn(new LogMaker( MetricsProto.MetricsEvent.VIEW_UNKNOWN)); ArgumentCaptor<OnMenuEventListener> onMenuEventListenerArgumentCaptor = ArgumentCaptor.forClass(OnMenuEventListener.class); mController.attach(mNotificationStackScrollLayout); verify(mNotificationStackScrollLayout).setMenuEventListener( onMenuEventListenerArgumentCaptor.capture()); OnMenuEventListener onMenuEventListener = onMenuEventListenerArgumentCaptor.getValue(); onMenuEventListener.onMenuShown(row); verify(row.getEntry().getSbn()).getLogMaker(); // This writes most of the log data verify(mMetricsLogger).write(logMatcher(MetricsProto.MetricsEvent.ACTION_REVEAL_GEAR, MetricsProto.MetricsEvent.TYPE_ACTION)); } @Test public void testOnMenuClickedLogging() { ExpandableNotificationRow row = mock(ExpandableNotificationRow.class, RETURNS_DEEP_STUBS); when(row.getEntry().getSbn().getLogMaker()).thenReturn(new LogMaker( MetricsProto.MetricsEvent.VIEW_UNKNOWN)); ArgumentCaptor<OnMenuEventListener> onMenuEventListenerArgumentCaptor = ArgumentCaptor.forClass(OnMenuEventListener.class); mController.attach(mNotificationStackScrollLayout); verify(mNotificationStackScrollLayout).setMenuEventListener( onMenuEventListenerArgumentCaptor.capture()); OnMenuEventListener onMenuEventListener = onMenuEventListenerArgumentCaptor.getValue(); onMenuEventListener.onMenuClicked(row, 0, 0, mock( NotificationMenuRowPlugin.MenuItem.class)); verify(row.getEntry().getSbn()).getLogMaker(); // This writes most of the log data verify(mMetricsLogger).write(logMatcher(MetricsProto.MetricsEvent.ACTION_TOUCH_GEAR, MetricsProto.MetricsEvent.TYPE_ACTION)); } private LogMaker logMatcher(int category, int type) { return argThat(new LogMatcher(category, type)); } static class LogMatcher implements ArgumentMatcher<LogMaker> { private int mCategory, mType; LogMatcher(int category, int type) { mCategory = category; mType = type; } public boolean matches(LogMaker l) { return (l.getCategory() == mCategory) && (l.getType() == mType); } public String toString() { return String.format("LogMaker(%d, %d)", mCategory, mType); } } }