Merge "Move OnMenuEventListener out of NSSL"

This commit is contained in:
TreeHugger Robot
2020-08-19 00:59:16 +00:00
committed by Android (Google) Code Review
4 changed files with 194 additions and 135 deletions

View File

@@ -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;
@@ -316,7 +317,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
* motion.
*/
private int mMaxScrollAfterExpand;
private ExpandableNotificationRow.LongPressListener mLongPressListener;
boolean mCheckForLeavebehind;
/**
@@ -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);
@@ -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
@@ -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
*/
@@ -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 =

View File

@@ -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;
@@ -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;
@@ -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;
@@ -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;
@@ -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,
@@ -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;
@@ -203,6 +267,7 @@ public class NotificationStackScrollLayoutController {
mZenModeController = zenModeController;
mColorExtractor = colorExtractor;
mLockscreenUserManager = lockscreenUserManager;
mMetricsLogger = metricsLogger;
}
public void attach(NotificationStackScrollLayout view) {
@@ -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);

View File

@@ -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;
@@ -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;
@@ -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;
@@ -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);

View File

@@ -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;
@@ -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;
@@ -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() {
@@ -102,7 +114,9 @@ public class NotificationStackScrollerControllerTest extends SysuiTestCase {
mKeyguardBypassController,
mZenModeController,
mColorExtractor,
mNotificationLockscreenUserManager);
mNotificationLockscreenUserManager,
mMetricsLogger
);
when(mNotificationStackScrollLayout.isAttachedToWindow()).thenReturn(true);
}
@@ -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);
}
}
}