Loading packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java +38 −3 Original line number Diff line number Diff line Loading @@ -586,6 +586,8 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump private boolean mGestureWaitForTouchSlop; private boolean mIgnoreXTouchSlop; private boolean mExpandLatencyTracking; private boolean mUseExternalTouch = false; /** * Whether we're waking up and will play the delayed doze animation in * {@link NotificationWakeUpCoordinator}. If so, we'll want to keep the clock centered until the Loading Loading @@ -4114,12 +4116,22 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump /** Sends an external (e.g. Status Bar) intercept touch event to the Shade touch handler. */ boolean handleExternalInterceptTouch(MotionEvent event) { try { mUseExternalTouch = true; return mTouchHandler.onInterceptTouchEvent(event); } finally { mUseExternalTouch = false; } } @Override public boolean handleExternalTouch(MotionEvent event) { try { mUseExternalTouch = true; return mTouchHandler.onTouchEvent(event); } finally { mUseExternalTouch = false; } } @Override Loading Loading @@ -4706,9 +4718,20 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump public final class TouchHandler implements View.OnTouchListener, Gefingerpoken { private long mLastTouchDownTime = -1L; /** @see ViewGroup#onInterceptTouchEvent(MotionEvent) */ /** * With the shade and lockscreen being separated in the view hierarchy, touch handling now * originates with the parent window through {@link #handleExternalTouch}. This allows for * parity with the legacy hierarchy while not undertaking a massive refactoring of touch * handling. * * @see NotificationShadeWindowViewController#didNotificationPanelInterceptEvent */ @Override public boolean onInterceptTouchEvent(MotionEvent event) { if (mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL) && !mUseExternalTouch) { return false; } mShadeLog.logMotionEvent(event, "NPVC onInterceptTouchEvent"); if (mQsController.disallowTouches()) { mShadeLog.logMotionEvent(event, Loading Loading @@ -4861,8 +4884,20 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump return onTouchEvent(event); } /** * With the shade and lockscreen being separated in the view hierarchy, touch handling now * originates with the parent window through {@link #handleExternalTouch}. This allows for * parity with the legacy hierarchy while not undertaking a massive refactoring of touch * handling. * * @see NotificationShadeWindowViewController#didNotificationPanelInterceptEvent */ @Override public boolean onTouchEvent(MotionEvent event) { if (mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL) && !mUseExternalTouch) { return false; } if (event.getAction() == MotionEvent.ACTION_DOWN) { if (event.getDownTime() == mLastTouchDownTime) { // An issue can occur when swiping down after unlock, where multiple down Loading packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java +72 −20 Original line number Diff line number Diff line Loading @@ -267,6 +267,9 @@ public class NotificationShadeWindowViewController implements Dumpable { } mView.setLayoutInsetsController(mNotificationInsetsController); mView.setInteractionEventHandler(new NotificationShadeWindowView.InteractionEventHandler() { boolean mUseDragDownHelperForTouch = false; boolean mLastInterceptWasDragDownHelper = false; @Override public Boolean handleDispatchTouchEvent(MotionEvent ev) { if (mStatusBarViewController == null) { // Fix for b/192490822 Loading Loading @@ -360,10 +363,8 @@ public class NotificationShadeWindowViewController implements Dumpable { ); // In case we start outside of the view bounds (below the status bar), we need to // dispatch // the touch manually as the view system can't accommodate for touches outside of // the // regular view bounds. // dispatch the touch manually as the view system can't accommodate for touches // outside of the regular view bounds. if (isDown && ev.getY() >= mView.getBottom()) { mExpandingBelowNotch = true; expandingBelowNotch = true; Loading Loading @@ -405,6 +406,15 @@ public class NotificationShadeWindowViewController implements Dumpable { @Override public boolean shouldInterceptTouchEvent(MotionEvent ev) { boolean intercepted = shouldInterceptTouchEventInternal(ev); if (intercepted) { mUseDragDownHelperForTouch = mLastInterceptWasDragDownHelper; } return intercepted; } private boolean shouldInterceptTouchEventInternal(MotionEvent ev) { mLastInterceptWasDragDownHelper = false; if (mStatusBarStateController.isDozing() && !mDozeServiceHost.isPulsing() && !mDockManager.isDocked()) { if (ev.getAction() == MotionEvent.ACTION_DOWN) { Loading @@ -431,27 +441,46 @@ public class NotificationShadeWindowViewController implements Dumpable { } if (mNotificationPanelViewController.isFullyExpanded() && mDragDownHelper.isDragDownEnabled() && !mService.isBouncerShowing() && !mStatusBarStateController.isDozing()) { if (mDragDownHelper.isDragDownEnabled()) { // This handles drag down over lockscreen boolean result = mDragDownHelper.onInterceptTouchEvent(ev); if (mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL)) { if (result) { mLastInterceptWasDragDownHelper = true; if (ev.getAction() == MotionEvent.ACTION_DOWN) { mShadeLogger.d("NSWVC: drag down helper intercepted"); } } else if (didNotificationPanelInterceptEvent(ev)) { return true; } } else { if (result) { if (ev.getAction() == MotionEvent.ACTION_DOWN) { mShadeLogger.d("NSWVC: drag down helper intercepted"); } } } return result; } else { return false; // This else handles interactions on the full shade while unlocked if (didNotificationPanelInterceptEvent(ev)) { return true; } } } return false; } @Override public void didIntercept(MotionEvent ev) { MotionEvent cancellation = MotionEvent.obtain(ev); cancellation.setAction(MotionEvent.ACTION_CANCEL); mStackScrollLayout.onInterceptTouchEvent(cancellation); if (!mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL)) { mNotificationPanelViewController.handleExternalInterceptTouch(cancellation); } cancellation.recycle(); } Loading @@ -461,11 +490,18 @@ public class NotificationShadeWindowViewController implements Dumpable { if (mStatusBarStateController.isDozing()) { handled = !mDozeServiceHost.isPulsing(); } if (mStatusBarKeyguardViewManager.onTouch(ev)) { return true; } if (mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL)) { if (mLastInterceptWasDragDownHelper && (mDragDownHelper.isDraggingDown())) { // we still want to finish our drag down gesture when locking the screen handled |= mDragDownHelper.onTouchEvent(ev) || handled; } if (!handled && mNotificationPanelViewController.handleExternalTouch(ev)) { return true; } } else { if (mDragDownHelper.isDragDownEnabled() || mDragDownHelper.isDraggingDown()) { // we still want to finish our drag down gesture when locking the screen Loading @@ -474,6 +510,8 @@ public class NotificationShadeWindowViewController implements Dumpable { return handled; } } return handled; } @Override public void didNotHandleTouchEvent(MotionEvent ev) { Loading Loading @@ -520,6 +558,20 @@ public class NotificationShadeWindowViewController implements Dumpable { mDepthController.onPanelExpansionChanged(currentState); } private boolean didNotificationPanelInterceptEvent(MotionEvent ev) { if (mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL)) { // Since NotificationStackScrollLayout is now a sibling of notification_panel, we need // to also ask NotificationPanelViewController directly, in order to process swipe up // events originating from notifications if (mNotificationPanelViewController.handleExternalInterceptTouch(ev)) { mShadeLogger.d("NSWVC: NPVC intercepted"); return true; } } return false; } public NotificationShadeWindowView getView() { return mView; } Loading packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java +7 −2 Original line number Diff line number Diff line Loading @@ -70,6 +70,7 @@ import com.android.systemui.classifier.Classifier; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dump.DumpManager; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.Flags; import com.android.systemui.fragments.FragmentHostManager; import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor; import com.android.systemui.media.controls.pipeline.MediaDataManager; Loading Loading @@ -1776,8 +1777,10 @@ public class QuickSettingsController implements Dumpable { // Dragging down on the lockscreen statusbar should prohibit other interactions // immediately, otherwise we'll wait on the touchslop. This is to allow // dragging down to expanded quick settings directly on the lockscreen. if (!mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL)) { mPanelView.getParent().requestDisallowInterceptTouchEvent(true); } } if (mExpansionAnimator != null) { mInitialHeightOnTouch = mExpansionHeight; mShadeLog.logMotionEvent(event, Loading Loading @@ -1819,7 +1822,9 @@ public class QuickSettingsController implements Dumpable { && Math.abs(h) > Math.abs(x - mInitialTouchX) && shouldQuickSettingsIntercept( mInitialTouchX, mInitialTouchY, h)) { if (!mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL)) { mPanelView.getParent().requestDisallowInterceptTouchEvent(true); } mShadeLog.onQsInterceptMoveQsTrackingEnabled(h); setTracking(true); traceQsJank(true, false); Loading packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java +3 −1 Original line number Diff line number Diff line Loading @@ -1545,7 +1545,9 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { return (v, event) -> { mAutoHideController.checkUserAutoHide(event); mRemoteInputManager.checkRemoteInputOutside(event); if (!mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL)) { mShadeController.onStatusBarTouch(event); } return getNotificationShadeWindowView().onTouchEvent(event); }; } Loading packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java +12 −0 Original line number Diff line number Diff line Loading @@ -59,6 +59,7 @@ import androidx.test.filters.SmallTest; import com.android.keyguard.FaceAuthApiRequestReason; import com.android.systemui.DejankUtils; import com.android.systemui.R; import com.android.systemui.flags.Flags; import com.android.systemui.keyguard.shared.model.WakeSleepReason; import com.android.systemui.keyguard.shared.model.WakefulnessModel; import com.android.systemui.keyguard.shared.model.WakefulnessState; Loading Loading @@ -1064,7 +1065,18 @@ public class NotificationPanelViewControllerTest extends NotificationPanelViewCo mEmptySpaceClickListenerCaptor.getValue().onEmptySpaceClicked(0, 0); verify(mUpdateMonitor, never()).requestFaceAuth(anyString()); } @Test public void nsslFlagEnabled_allowOnlyExternalTouches() { when(mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL)).thenReturn(true); // This sets the dozing state that is read when onMiddleClicked is eventually invoked. mTouchHandler.onTouch(mock(View.class), mDownMotionEvent); verify(mQsController, never()).disallowTouches(); mNotificationPanelViewController.handleExternalInterceptTouch(mDownMotionEvent); verify(mQsController).disallowTouches(); } @Test Loading Loading
packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java +38 −3 Original line number Diff line number Diff line Loading @@ -586,6 +586,8 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump private boolean mGestureWaitForTouchSlop; private boolean mIgnoreXTouchSlop; private boolean mExpandLatencyTracking; private boolean mUseExternalTouch = false; /** * Whether we're waking up and will play the delayed doze animation in * {@link NotificationWakeUpCoordinator}. If so, we'll want to keep the clock centered until the Loading Loading @@ -4114,12 +4116,22 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump /** Sends an external (e.g. Status Bar) intercept touch event to the Shade touch handler. */ boolean handleExternalInterceptTouch(MotionEvent event) { try { mUseExternalTouch = true; return mTouchHandler.onInterceptTouchEvent(event); } finally { mUseExternalTouch = false; } } @Override public boolean handleExternalTouch(MotionEvent event) { try { mUseExternalTouch = true; return mTouchHandler.onTouchEvent(event); } finally { mUseExternalTouch = false; } } @Override Loading Loading @@ -4706,9 +4718,20 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump public final class TouchHandler implements View.OnTouchListener, Gefingerpoken { private long mLastTouchDownTime = -1L; /** @see ViewGroup#onInterceptTouchEvent(MotionEvent) */ /** * With the shade and lockscreen being separated in the view hierarchy, touch handling now * originates with the parent window through {@link #handleExternalTouch}. This allows for * parity with the legacy hierarchy while not undertaking a massive refactoring of touch * handling. * * @see NotificationShadeWindowViewController#didNotificationPanelInterceptEvent */ @Override public boolean onInterceptTouchEvent(MotionEvent event) { if (mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL) && !mUseExternalTouch) { return false; } mShadeLog.logMotionEvent(event, "NPVC onInterceptTouchEvent"); if (mQsController.disallowTouches()) { mShadeLog.logMotionEvent(event, Loading Loading @@ -4861,8 +4884,20 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump return onTouchEvent(event); } /** * With the shade and lockscreen being separated in the view hierarchy, touch handling now * originates with the parent window through {@link #handleExternalTouch}. This allows for * parity with the legacy hierarchy while not undertaking a massive refactoring of touch * handling. * * @see NotificationShadeWindowViewController#didNotificationPanelInterceptEvent */ @Override public boolean onTouchEvent(MotionEvent event) { if (mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL) && !mUseExternalTouch) { return false; } if (event.getAction() == MotionEvent.ACTION_DOWN) { if (event.getDownTime() == mLastTouchDownTime) { // An issue can occur when swiping down after unlock, where multiple down Loading
packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java +72 −20 Original line number Diff line number Diff line Loading @@ -267,6 +267,9 @@ public class NotificationShadeWindowViewController implements Dumpable { } mView.setLayoutInsetsController(mNotificationInsetsController); mView.setInteractionEventHandler(new NotificationShadeWindowView.InteractionEventHandler() { boolean mUseDragDownHelperForTouch = false; boolean mLastInterceptWasDragDownHelper = false; @Override public Boolean handleDispatchTouchEvent(MotionEvent ev) { if (mStatusBarViewController == null) { // Fix for b/192490822 Loading Loading @@ -360,10 +363,8 @@ public class NotificationShadeWindowViewController implements Dumpable { ); // In case we start outside of the view bounds (below the status bar), we need to // dispatch // the touch manually as the view system can't accommodate for touches outside of // the // regular view bounds. // dispatch the touch manually as the view system can't accommodate for touches // outside of the regular view bounds. if (isDown && ev.getY() >= mView.getBottom()) { mExpandingBelowNotch = true; expandingBelowNotch = true; Loading Loading @@ -405,6 +406,15 @@ public class NotificationShadeWindowViewController implements Dumpable { @Override public boolean shouldInterceptTouchEvent(MotionEvent ev) { boolean intercepted = shouldInterceptTouchEventInternal(ev); if (intercepted) { mUseDragDownHelperForTouch = mLastInterceptWasDragDownHelper; } return intercepted; } private boolean shouldInterceptTouchEventInternal(MotionEvent ev) { mLastInterceptWasDragDownHelper = false; if (mStatusBarStateController.isDozing() && !mDozeServiceHost.isPulsing() && !mDockManager.isDocked()) { if (ev.getAction() == MotionEvent.ACTION_DOWN) { Loading @@ -431,27 +441,46 @@ public class NotificationShadeWindowViewController implements Dumpable { } if (mNotificationPanelViewController.isFullyExpanded() && mDragDownHelper.isDragDownEnabled() && !mService.isBouncerShowing() && !mStatusBarStateController.isDozing()) { if (mDragDownHelper.isDragDownEnabled()) { // This handles drag down over lockscreen boolean result = mDragDownHelper.onInterceptTouchEvent(ev); if (mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL)) { if (result) { mLastInterceptWasDragDownHelper = true; if (ev.getAction() == MotionEvent.ACTION_DOWN) { mShadeLogger.d("NSWVC: drag down helper intercepted"); } } else if (didNotificationPanelInterceptEvent(ev)) { return true; } } else { if (result) { if (ev.getAction() == MotionEvent.ACTION_DOWN) { mShadeLogger.d("NSWVC: drag down helper intercepted"); } } } return result; } else { return false; // This else handles interactions on the full shade while unlocked if (didNotificationPanelInterceptEvent(ev)) { return true; } } } return false; } @Override public void didIntercept(MotionEvent ev) { MotionEvent cancellation = MotionEvent.obtain(ev); cancellation.setAction(MotionEvent.ACTION_CANCEL); mStackScrollLayout.onInterceptTouchEvent(cancellation); if (!mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL)) { mNotificationPanelViewController.handleExternalInterceptTouch(cancellation); } cancellation.recycle(); } Loading @@ -461,11 +490,18 @@ public class NotificationShadeWindowViewController implements Dumpable { if (mStatusBarStateController.isDozing()) { handled = !mDozeServiceHost.isPulsing(); } if (mStatusBarKeyguardViewManager.onTouch(ev)) { return true; } if (mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL)) { if (mLastInterceptWasDragDownHelper && (mDragDownHelper.isDraggingDown())) { // we still want to finish our drag down gesture when locking the screen handled |= mDragDownHelper.onTouchEvent(ev) || handled; } if (!handled && mNotificationPanelViewController.handleExternalTouch(ev)) { return true; } } else { if (mDragDownHelper.isDragDownEnabled() || mDragDownHelper.isDraggingDown()) { // we still want to finish our drag down gesture when locking the screen Loading @@ -474,6 +510,8 @@ public class NotificationShadeWindowViewController implements Dumpable { return handled; } } return handled; } @Override public void didNotHandleTouchEvent(MotionEvent ev) { Loading Loading @@ -520,6 +558,20 @@ public class NotificationShadeWindowViewController implements Dumpable { mDepthController.onPanelExpansionChanged(currentState); } private boolean didNotificationPanelInterceptEvent(MotionEvent ev) { if (mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL)) { // Since NotificationStackScrollLayout is now a sibling of notification_panel, we need // to also ask NotificationPanelViewController directly, in order to process swipe up // events originating from notifications if (mNotificationPanelViewController.handleExternalInterceptTouch(ev)) { mShadeLogger.d("NSWVC: NPVC intercepted"); return true; } } return false; } public NotificationShadeWindowView getView() { return mView; } Loading
packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java +7 −2 Original line number Diff line number Diff line Loading @@ -70,6 +70,7 @@ import com.android.systemui.classifier.Classifier; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dump.DumpManager; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.Flags; import com.android.systemui.fragments.FragmentHostManager; import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor; import com.android.systemui.media.controls.pipeline.MediaDataManager; Loading Loading @@ -1776,8 +1777,10 @@ public class QuickSettingsController implements Dumpable { // Dragging down on the lockscreen statusbar should prohibit other interactions // immediately, otherwise we'll wait on the touchslop. This is to allow // dragging down to expanded quick settings directly on the lockscreen. if (!mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL)) { mPanelView.getParent().requestDisallowInterceptTouchEvent(true); } } if (mExpansionAnimator != null) { mInitialHeightOnTouch = mExpansionHeight; mShadeLog.logMotionEvent(event, Loading Loading @@ -1819,7 +1822,9 @@ public class QuickSettingsController implements Dumpable { && Math.abs(h) > Math.abs(x - mInitialTouchX) && shouldQuickSettingsIntercept( mInitialTouchX, mInitialTouchY, h)) { if (!mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL)) { mPanelView.getParent().requestDisallowInterceptTouchEvent(true); } mShadeLog.onQsInterceptMoveQsTrackingEnabled(h); setTracking(true); traceQsJank(true, false); Loading
packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java +3 −1 Original line number Diff line number Diff line Loading @@ -1545,7 +1545,9 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { return (v, event) -> { mAutoHideController.checkUserAutoHide(event); mRemoteInputManager.checkRemoteInputOutside(event); if (!mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL)) { mShadeController.onStatusBarTouch(event); } return getNotificationShadeWindowView().onTouchEvent(event); }; } Loading
packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java +12 −0 Original line number Diff line number Diff line Loading @@ -59,6 +59,7 @@ import androidx.test.filters.SmallTest; import com.android.keyguard.FaceAuthApiRequestReason; import com.android.systemui.DejankUtils; import com.android.systemui.R; import com.android.systemui.flags.Flags; import com.android.systemui.keyguard.shared.model.WakeSleepReason; import com.android.systemui.keyguard.shared.model.WakefulnessModel; import com.android.systemui.keyguard.shared.model.WakefulnessState; Loading Loading @@ -1064,7 +1065,18 @@ public class NotificationPanelViewControllerTest extends NotificationPanelViewCo mEmptySpaceClickListenerCaptor.getValue().onEmptySpaceClicked(0, 0); verify(mUpdateMonitor, never()).requestFaceAuth(anyString()); } @Test public void nsslFlagEnabled_allowOnlyExternalTouches() { when(mFeatureFlags.isEnabled(Flags.MIGRATE_NSSL)).thenReturn(true); // This sets the dozing state that is read when onMiddleClicked is eventually invoked. mTouchHandler.onTouch(mock(View.class), mDownMotionEvent); verify(mQsController, never()).disallowTouches(); mNotificationPanelViewController.handleExternalInterceptTouch(mDownMotionEvent); verify(mQsController).disallowTouches(); } @Test Loading