diff options
4 files changed, 205 insertions, 18 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NPVCDownEventState.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NPVCDownEventState.kt new file mode 100644 index 000000000000..06235071734e --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NPVCDownEventState.kt @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ +package com.android.systemui.statusbar.phone + +import android.view.MotionEvent +import com.android.internal.util.RingBuffer +import com.android.systemui.dump.DumpsysTableLogger +import com.android.systemui.dump.Row +import java.text.SimpleDateFormat +import java.util.Locale + +/** Container for storing information about [MotionEvent.ACTION_DOWN] on + * [NotificationPanelViewController]. + * + * This will be used in a dump to log the latest recorded down events. + * + * @see NotificationPanelViewController.initDownStates + */ +class NPVCDownEventState private constructor( + private var timeStamp: Long = 0, + private var x: Float = 0f, + private var y: Float = 0f, + private var qsTouchAboveFalsingThreshold: Boolean = false, + private var dozing: Boolean = false, + private var collapsed: Boolean = false, + private var canCollapseOnQQS: Boolean = false, + private var listenForHeadsUp: Boolean = false, + private var allowExpandForSmallExpansion: Boolean = false, + private var touchSlopExceededBeforeDown: Boolean = false, + private var lastEventSynthesized: Boolean = false +) { + + /** + * List of [String] to be used as a [Row] with [DumpsysTableLogger]. + */ + val asStringList: List<String> by lazy { + listOf( + DATE_FORMAT.format(timeStamp), + x.toString(), + y.toString(), + qsTouchAboveFalsingThreshold.toString(), + dozing.toString(), + collapsed.toString(), + canCollapseOnQQS.toString(), + listenForHeadsUp.toString(), + allowExpandForSmallExpansion.toString(), + touchSlopExceededBeforeDown.toString(), + lastEventSynthesized.toString() + ) + } + + /** + * [RingBuffer] to store [NPVCDownEventState]. After the buffer is full, it will recycle old + * events. + * + * Do not use [append] to add new elements. Instead use [insert], as it will recycle if + * necessary. + */ + class Buffer( + capacity: Int + ) : RingBuffer<NPVCDownEventState>(NPVCDownEventState::class.java, capacity) { + override fun append(t: NPVCDownEventState?) { + throw UnsupportedOperationException("Not supported, use insert instead") + } + + override fun createNewItem(): NPVCDownEventState { + return NPVCDownEventState() + } + + /** + * Insert a new element in the buffer. + */ + fun insert( + timeStamp: Long, + x: Float, + y: Float, + qsTouchAboveFalsingThreshold: Boolean, + dozing: Boolean, + collapsed: Boolean, + canCollapseOnQQS: Boolean, + listenForHeadsUp: Boolean, + allowExpandForSmallExpansion: Boolean, + touchSlopExceededBeforeDown: Boolean, + lastEventSynthesized: Boolean + ) { + nextSlot.apply { + this.timeStamp = timeStamp + this.x = x + this.y = y + this.qsTouchAboveFalsingThreshold = qsTouchAboveFalsingThreshold + this.dozing = dozing + this.collapsed = collapsed + this.canCollapseOnQQS = canCollapseOnQQS + this.listenForHeadsUp = listenForHeadsUp + this.allowExpandForSmallExpansion = allowExpandForSmallExpansion + this.touchSlopExceededBeforeDown = touchSlopExceededBeforeDown + this.lastEventSynthesized = lastEventSynthesized + } + } + + /** + * Returns the content of the buffer (sorted from latest to newest). + * + * @see NPVCDownEventState.asStringList + */ + fun toList(): List<Row> { + return toArray().map { it.asStringList } + } + } + + companion object { + /** + * Headers for dumping a table using [DumpsysTableLogger]. + */ + @JvmField + val TABLE_HEADERS = listOf( + "Timestamp", + "X", + "Y", + "QSTouchAboveFalsingThreshold", + "Dozing", + "Collapsed", + "CanCollapseOnQQS", + "ListenForHeadsUp", + "AllowExpandForSmallExpansion", + "TouchSlopExceededBeforeDown", + "LastEventSynthesized" + ) + } +} + +private val DATE_FORMAT = SimpleDateFormat("MM-dd HH:mm:ss.SSS", Locale.US) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java index b5789fb9c634..985df423d744 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java @@ -36,6 +36,7 @@ import static com.android.systemui.statusbar.notification.stack.StackStateAnimat import static com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManagerKt.STATE_CLOSED; import static com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManagerKt.STATE_OPEN; import static com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManagerKt.STATE_OPENING; +import static com.android.systemui.util.DumpUtilsKt.asIndenting; import static java.lang.Float.isNaN; @@ -65,13 +66,13 @@ import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.os.Bundle; import android.os.Handler; import android.os.PowerManager; -import android.os.SystemClock; import android.os.Trace; import android.os.UserManager; import android.os.VibrationEffect; import android.provider.Settings; import android.transition.ChangeBounds; import android.transition.TransitionManager; +import android.util.IndentingPrintWriter; import android.util.Log; import android.util.MathUtils; import android.view.LayoutInflater; @@ -121,6 +122,7 @@ import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.DisplayId; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.doze.DozeLog; +import com.android.systemui.dump.DumpsysTableLogger; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.Flags; import com.android.systemui.fragments.FragmentHostManager.FragmentListener; @@ -193,6 +195,7 @@ import com.android.systemui.util.LargeScreenUtils; import com.android.systemui.util.ListenerSet; import com.android.systemui.util.Utils; import com.android.systemui.util.settings.SecureSettings; +import com.android.systemui.util.time.SystemClock; import com.android.systemui.wallet.controller.QuickAccessWalletController; import com.android.wm.shell.animation.FlingAnimationUtils; @@ -212,7 +215,7 @@ import javax.inject.Provider; @CentralSurfacesComponent.CentralSurfacesScope public class NotificationPanelViewController extends PanelViewController { - private static final boolean DEBUG = false; + private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); /** * The parallax amount of the quick settings translation when dragging down the panel @@ -279,6 +282,8 @@ public class NotificationPanelViewController extends PanelViewController { */ private static final int MAX_TIME_TO_OPEN_WHEN_FLINGING_FROM_LAUNCHER = 300; + private static final int MAX_DOWN_EVENT_BUFFER_SIZE = 50; + private static final String COUNTER_PANEL_OPEN = "panel_open"; private static final String COUNTER_PANEL_OPEN_QS = "panel_open_qs"; private static final String COUNTER_PANEL_OPEN_PEEK = "panel_open_peek"; @@ -653,6 +658,8 @@ public class NotificationPanelViewController extends PanelViewController { private final NotificationListContainer mNotificationListContainer; private final NotificationStackSizeCalculator mNotificationStackSizeCalculator; + private final NPVCDownEventState.Buffer mLastDownEvents; + private View.AccessibilityDelegate mAccessibilityDelegate = new View.AccessibilityDelegate() { @Override public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) { @@ -755,7 +762,8 @@ public class NotificationPanelViewController extends PanelViewController { PanelEventsEmitter panelEventsEmitter, NotificationStackSizeCalculator notificationStackSizeCalculator, UnlockedScreenOffAnimationController unlockedScreenOffAnimationController, - ShadeTransitionController shadeTransitionController) { + ShadeTransitionController shadeTransitionController, + SystemClock systemClock) { super(view, falsingManager, dozeLog, @@ -771,7 +779,8 @@ public class NotificationPanelViewController extends PanelViewController { panelExpansionStateManager, ambientState, interactionJankMonitor, - keyguardUnlockAnimationController); + keyguardUnlockAnimationController, + systemClock); mView = view; mVibratorHelper = vibratorHelper; mKeyguardMediaController = keyguardMediaController; @@ -860,6 +869,7 @@ public class NotificationPanelViewController extends PanelViewController { mScreenOffAnimationController = screenOffAnimationController; mUnlockedScreenOffAnimationController = unlockedScreenOffAnimationController; mRemoteInputManager = remoteInputManager; + mLastDownEvents = new NPVCDownEventState.Buffer(MAX_DOWN_EVENT_BUFFER_SIZE); int currentMode = navigationModeController.addListener( mode -> mIsGestureNavigation = QuickStepContract.isGesturalMode(mode)); @@ -1709,6 +1719,7 @@ public class NotificationPanelViewController extends PanelViewController { } private boolean onQsIntercept(MotionEvent event) { + if (DEBUG) Log.d(TAG, "onQsIntercept"); int pointerIndex = event.findPointerIndex(mTrackingPointer); if (pointerIndex < 0) { pointerIndex = 0; @@ -1763,6 +1774,7 @@ public class NotificationPanelViewController extends PanelViewController { if ((h > getTouchSlop(event) || (h < -getTouchSlop(event) && mQsExpanded)) && Math.abs(h) > Math.abs(x - mInitialTouchX) && shouldQuickSettingsIntercept(mInitialTouchX, mInitialTouchY, h)) { + if (DEBUG) Log.d(TAG, "onQsIntercept - start tracking expansion"); mView.getParent().requestDisallowInterceptTouchEvent(true); mQsTracking = true; traceQsJank(true /* startTracing */, false /* wasCancelled */); @@ -1832,6 +1844,19 @@ public class NotificationPanelViewController extends PanelViewController { // down but not synthesized motion event. mLastEventSynthesizedDown = false; } + mLastDownEvents.insert( + mSystemClock.currentTimeMillis(), + mDownX, + mDownY, + mQsTouchAboveFalsingThreshold, + mDozingOnDown, + mCollapsedOnDown, + mIsPanelCollapseOnQQS, + mListenForHeadsUp, + mAllowExpandForSmallExpansion, + mTouchSlopExceededBeforeDown, + mLastEventSynthesizedDown + ); } else { // not down event at all. mLastEventSynthesizedDown = false; @@ -1925,7 +1950,7 @@ public class NotificationPanelViewController extends PanelViewController { if (mAllowExpandForSmallExpansion) { // When we get a touch that came over from launcher, the velocity isn't always correct // Let's err on expanding if the gesture has been reasonably slow - long timeSinceDown = SystemClock.uptimeMillis() - mDownTime; + long timeSinceDown = mSystemClock.uptimeMillis() - mDownTime; return timeSinceDown <= MAX_TIME_TO_OPEN_WHEN_FLINGING_FROM_LAUNCHER; } return false; @@ -1952,8 +1977,8 @@ public class NotificationPanelViewController extends PanelViewController { mConflictingQsExpansionGesture = true; onQsExpansionStarted(); mInitialHeightOnTouch = mQsExpansionHeight; - mInitialTouchY = event.getX(); - mInitialTouchX = event.getY(); + mInitialTouchY = event.getY(); + mInitialTouchX = event.getX(); } if (!isFullyCollapsed()) { handleQsDown(event); @@ -2026,12 +2051,13 @@ public class NotificationPanelViewController extends PanelViewController { private void handleQsDown(MotionEvent event) { if (event.getActionMasked() == MotionEvent.ACTION_DOWN && shouldQuickSettingsIntercept( event.getX(), event.getY(), -1)) { + if (DEBUG) Log.d(TAG, "handleQsDown"); mFalsingCollector.onQsDown(); mQsTracking = true; onQsExpansionStarted(); mInitialHeightOnTouch = mQsExpansionHeight; - mInitialTouchY = event.getX(); - mInitialTouchX = event.getY(); + mInitialTouchY = event.getY(); + mInitialTouchX = event.getX(); // If we interrupt an expansion gesture here, make sure to update the state correctly. notifyExpandingFinished(); @@ -2139,6 +2165,7 @@ public class NotificationPanelViewController extends PanelViewController { break; case MotionEvent.ACTION_MOVE: + if (DEBUG) Log.d(TAG, "onQSTouch move"); setQsExpansion(h + mInitialHeightOnTouch); if (h >= getFalsingThreshold()) { mQsTouchAboveFalsingThreshold = true; @@ -3872,10 +3899,18 @@ public class NotificationPanelViewController extends PanelViewController { @Override public void dump(PrintWriter pw, String[] args) { super.dump(pw, args); - pw.println(" gestureExclusionRect: " + calculateGestureExclusionRect() - + " applyQSClippingImmediately: top(" + mQsClipTop + ") bottom(" + mQsClipBottom - + ") qsVisible(" + mQsVisible - ); + IndentingPrintWriter ipw = asIndenting(pw); + ipw.increaseIndent(); + ipw.println("gestureExclusionRect:" + calculateGestureExclusionRect()); + ipw.println("applyQSClippingImmediately: top(" + mQsClipTop + ") bottom(" + mQsClipBottom + + ")"); + ipw.println("qsVisible:" + mQsVisible); + new DumpsysTableLogger( + TAG, + NPVCDownEventState.TABLE_HEADERS, + mLastDownEvents.toList() + ).printTableData(ipw); + ipw.decreaseIndent(); if (mKeyguardStatusBarViewController != null) { mKeyguardStatusBarViewController.dump(pw, args); } @@ -4042,6 +4077,7 @@ public class NotificationPanelViewController extends PanelViewController { } if (!isFullyCollapsed() && onQsIntercept(event)) { + if (DEBUG) Log.d(TAG, "onQsIntercept true"); return true; } return super.onInterceptTouchEvent(event); @@ -4112,6 +4148,7 @@ public class NotificationPanelViewController extends PanelViewController { handled |= mHeadsUpTouchHelper.onTouchEvent(event); if (!mHeadsUpTouchHelper.isTrackingHeadsUp() && handleQsTouch(event)) { + if (DEBUG) Log.d(TAG, "handleQsTouch true"); return true; } if (event.getActionMasked() == MotionEvent.ACTION_DOWN && isFullyCollapsed()) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java index 6637394e2b2a..7ab944dc013e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java @@ -32,7 +32,6 @@ import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.content.res.Configuration; import android.content.res.Resources; -import android.os.SystemClock; import android.os.VibrationEffect; import android.util.Log; import android.util.MathUtils; @@ -63,6 +62,7 @@ import com.android.systemui.statusbar.notification.stack.AmbientState; import com.android.systemui.statusbar.phone.LockscreenGestureLogger.LockscreenUiEvent; import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager; import com.android.systemui.statusbar.policy.KeyguardStateController; +import com.android.systemui.util.time.SystemClock; import com.android.wm.shell.animation.FlingAnimationUtils; import java.io.PrintWriter; @@ -194,6 +194,7 @@ public abstract class PanelViewController { private final PanelExpansionStateManager mPanelExpansionStateManager; private final TouchHandler mTouchHandler; private final InteractionJankMonitor mInteractionJankMonitor; + protected final SystemClock mSystemClock; protected abstract void onExpandingFinished(); @@ -237,7 +238,8 @@ public abstract class PanelViewController { PanelExpansionStateManager panelExpansionStateManager, AmbientState ambientState, InteractionJankMonitor interactionJankMonitor, - KeyguardUnlockAnimationController keyguardUnlockAnimationController) { + KeyguardUnlockAnimationController keyguardUnlockAnimationController, + SystemClock systemClock) { mKeyguardUnlockAnimationController = keyguardUnlockAnimationController; keyguardStateController.addCallback(new KeyguardStateController.Callback() { @Override @@ -297,6 +299,7 @@ public abstract class PanelViewController { mVibrateOnOpening = mResources.getBoolean(R.bool.config_vibrateOnIconAnimation); mStatusBarTouchableRegionManager = statusBarTouchableRegionManager; mInteractionJankMonitor = interactionJankMonitor; + mSystemClock = systemClock; } protected void loadDimens() { @@ -1228,7 +1231,7 @@ public abstract class PanelViewController { mCentralSurfaces.userActivity(); mAnimatingOnDown = mHeightAnimator != null && !mIsSpringBackAnimation; mMinExpandHeight = 0.0f; - mDownTime = SystemClock.uptimeMillis(); + mDownTime = mSystemClock.uptimeMillis(); if (mAnimatingOnDown && mClosing && !mHintAnimationRunning) { cancelHeightAnimator(); mTouchSlopExceeded = true; @@ -1341,7 +1344,7 @@ public abstract class PanelViewController { mHasLayoutedSinceDown = false; mUpdateFlingOnLayout = false; mMotionAborted = false; - mDownTime = SystemClock.uptimeMillis(); + mDownTime = mSystemClock.uptimeMillis(); mTouchAboveFalsingThreshold = false; mCollapsedAndHeadsUpOnDown = isFullyCollapsed() && mHeadsUpManager.hasPinnedHeadsUp(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java index 6997b3e4bd70..94e6b9a12a93 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java @@ -139,6 +139,7 @@ import com.android.systemui.unfold.SysUIUnfoldComponent; import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.settings.SecureSettings; import com.android.systemui.util.time.FakeSystemClock; +import com.android.systemui.util.time.SystemClock; import com.android.systemui.wallet.controller.QuickAccessWalletController; import com.android.wm.shell.animation.FlingAnimationUtils; @@ -357,10 +358,12 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { private Handler mMainHandler; private final PanelExpansionStateManager mPanelExpansionStateManager = new PanelExpansionStateManager(); + private SystemClock mSystemClock; @Before public void setup() { MockitoAnnotations.initMocks(this); + mSystemClock = new FakeSystemClock(); mStatusBarStateController = new StatusBarStateControllerImpl(mUiEventLogger, mDumpManager, mInteractionJankMonitor); @@ -533,7 +536,8 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { mPanelEventsEmitter, mNotificationStackSizeCalculator, mUnlockedScreenOffAnimationController, - mShadeTransitionController); + mShadeTransitionController, + mSystemClock); mNotificationPanelViewController.initDependencies( mCentralSurfaces, () -> {}, |