diff options
| author | 2024-02-08 00:06:03 +0000 | |
|---|---|---|
| committer | 2024-04-29 17:34:00 -0700 | |
| commit | 73d4add6c260cbc1c63e2667066e6d4f5343b6f8 (patch) | |
| tree | b9b46af783c892d08a6d4aafdd5f765c82c4b7df | |
| parent | f0694c53eab5ab030d76dd66f2353396d4f6678e (diff) | |
Add jank tracker to back panel
Bug: 304583132
Bug: 304582856
Test: atest com.android.systemui.notetask.LaunchNotesRoleSettingsTrampolineActivityTest
Flag: ACONFIG com.android.systemui.edge_back_gesture_handler_thread DISABLED
Change-Id: I31be93d5d1e31058999e3597bc7170b38f01819f
2 files changed, 66 insertions, 16 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt index 30f33a3a2f6f..f8086f5f6fb4 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt @@ -21,19 +21,20 @@ import android.graphics.Color import android.graphics.Paint import android.graphics.Point import android.os.Handler -import android.os.SystemClock import android.util.Log import android.util.MathUtils import android.view.Gravity import android.view.HapticFeedbackConstants import android.view.MotionEvent import android.view.VelocityTracker +import android.view.View import android.view.ViewConfiguration import android.view.WindowManager import androidx.annotation.VisibleForTesting import androidx.core.os.postDelayed import androidx.core.view.isVisible import androidx.dynamicanimation.animation.DynamicAnimation +import com.android.internal.jank.Cuj import com.android.internal.jank.InteractionJankMonitor import com.android.internal.util.LatencyTracker import com.android.systemui.dagger.qualifiers.Main @@ -41,6 +42,7 @@ import com.android.systemui.plugins.NavigationEdgeBackPlugin import com.android.systemui.statusbar.VibratorHelper import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.util.ViewController +import com.android.systemui.util.time.SystemClock import java.io.PrintWriter import javax.inject.Inject import kotlin.math.abs @@ -84,6 +86,7 @@ internal constructor( private val windowManager: WindowManager, private val viewConfiguration: ViewConfiguration, @Main private val mainHandler: Handler, + private val systemClock: SystemClock, private val vibratorHelper: VibratorHelper, private val configurationController: ConfigurationController, private val latencyTracker: LatencyTracker, @@ -102,6 +105,7 @@ internal constructor( private val windowManager: WindowManager, private val viewConfiguration: ViewConfiguration, @Main private val mainHandler: Handler, + private val systemClock: SystemClock, private val vibratorHelper: VibratorHelper, private val configurationController: ConfigurationController, private val latencyTracker: LatencyTracker, @@ -115,6 +119,7 @@ internal constructor( windowManager, viewConfiguration, mainHandler, + systemClock, vibratorHelper, configurationController, latencyTracker, @@ -158,9 +163,9 @@ internal constructor( private var gestureInactiveTime = 0L private val elapsedTimeSinceInactive - get() = SystemClock.uptimeMillis() - gestureInactiveTime + get() = systemClock.uptimeMillis() - gestureInactiveTime private val elapsedTimeSinceEntry - get() = SystemClock.uptimeMillis() - gestureEntryTime + get() = systemClock.uptimeMillis() - gestureEntryTime private var pastThresholdWhileEntryOrInactiveTime = 0L private var entryToActiveDelay = 0F @@ -178,7 +183,7 @@ internal constructor( // Distance in pixels a drag can be considered for a fling event private var minFlingDistance = 0 - private val failsafeRunnable = Runnable { onFailsafe() } + internal val failsafeRunnable = Runnable { onFailsafe() } internal enum class GestureState { /* Arrow is off the screen and invisible */ @@ -370,6 +375,7 @@ internal constructor( // Receiving a CANCEL implies that something else intercepted // the gesture, i.e., the user did not cancel their gesture. // Therefore, disappear immediately, with minimum fanfare. + interactionJankMonitor.cancel(Cuj.CUJ_BACK_PANEL_ARROW) updateArrowState(GestureState.GONE) velocityTracker = null } @@ -692,10 +698,10 @@ internal constructor( } if (isPastThresholdForFirstTime) { - pastThresholdWhileEntryOrInactiveTime = SystemClock.uptimeMillis() + pastThresholdWhileEntryOrInactiveTime = systemClock.uptimeMillis() entryToActiveDelay = dynamicDelay() } - val timePastThreshold = SystemClock.uptimeMillis() - pastThresholdWhileEntryOrInactiveTime + val timePastThreshold = systemClock.uptimeMillis() - pastThresholdWhileEntryOrInactiveTime return timePastThreshold > entryToActiveDelay } @@ -881,6 +887,16 @@ internal constructor( previousState = currentState currentState = newState + // First, update the jank tracker + when (currentState) { + GestureState.ENTRY -> { + interactionJankMonitor.cancel(Cuj.CUJ_BACK_PANEL_ARROW) + interactionJankMonitor.begin(mView, Cuj.CUJ_BACK_PANEL_ARROW) + } + GestureState.GONE -> interactionJankMonitor.end(Cuj.CUJ_BACK_PANEL_ARROW) + else -> {} + } + when (currentState) { GestureState.CANCELLED -> { backCallback.cancelBack() @@ -912,7 +928,7 @@ internal constructor( mView.isVisible = true updateRestingArrowDimens() - gestureEntryTime = SystemClock.uptimeMillis() + gestureEntryTime = systemClock.uptimeMillis() } GestureState.ACTIVE -> { previousXTranslationOnActiveOffset = previousXTranslation @@ -927,7 +943,7 @@ internal constructor( mView.popOffEdge(popVelocity) } GestureState.INACTIVE -> { - gestureInactiveTime = SystemClock.uptimeMillis() + gestureInactiveTime = systemClock.uptimeMillis() // Typically entering INACTIVE means // totalTouchDelta <= deactivationSwipeTriggerThreshold @@ -1041,6 +1057,11 @@ internal constructor( pw.println(" isLeftPanel=${mView.isLeftPanel}") } + @VisibleForTesting + internal fun getBackPanelView(): BackPanel { + return mView + } + init { if (DEBUG) mView.drawDebugInfo = { canvas -> diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/gestural/BackPanelControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/gestural/BackPanelControllerTest.kt index e6c259abb456..f1c97dd45f09 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/gestural/BackPanelControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/gestural/BackPanelControllerTest.kt @@ -17,7 +17,6 @@ package com.android.systemui.navigationbar.gestural import android.os.Handler -import android.os.Looper import android.testing.AndroidTestingRunner import android.testing.TestableLooper import android.view.HapticFeedbackConstants @@ -28,6 +27,7 @@ import android.view.MotionEvent.ACTION_UP import android.view.ViewConfiguration import android.view.WindowManager import androidx.test.filters.SmallTest +import com.android.internal.jank.Cuj import com.android.internal.util.LatencyTracker import com.android.systemui.SysuiTestCase import com.android.systemui.jank.interactionJankMonitor @@ -35,6 +35,7 @@ import com.android.systemui.plugins.NavigationEdgeBackPlugin import com.android.systemui.statusbar.VibratorHelper import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.testKosmos +import com.android.systemui.util.time.FakeSystemClock import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Test @@ -43,6 +44,7 @@ import org.mockito.ArgumentMatchers.any import org.mockito.ArgumentMatchers.eq import org.mockito.Mock import org.mockito.Mockito.clearInvocations +import org.mockito.Mockito.never import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations @@ -55,6 +57,7 @@ class BackPanelControllerTest : SysuiTestCase() { } private val kosmos = testKosmos() private lateinit var mBackPanelController: BackPanelController + private lateinit var systemClock: FakeSystemClock private lateinit var testableLooper: TestableLooper private var triggerThreshold: Float = 0.0f private val touchSlop = ViewConfiguration.get(context).scaledEdgeSlop @@ -69,12 +72,15 @@ class BackPanelControllerTest : SysuiTestCase() { @Before fun setup() { MockitoAnnotations.initMocks(this) + testableLooper = TestableLooper.get(this) + systemClock = FakeSystemClock() mBackPanelController = BackPanelController( context, windowManager, ViewConfiguration.get(context), - Handler.createAsync(checkNotNull(Looper.myLooper())), + Handler.createAsync(testableLooper.looper), + systemClock, vibratorHelper, configurationController, latencyTracker, @@ -83,7 +89,6 @@ class BackPanelControllerTest : SysuiTestCase() { mBackPanelController.setLayoutParams(layoutParams) mBackPanelController.setBackCallback(backCallback) mBackPanelController.setIsLeftPanel(true) - testableLooper = TestableLooper.get(this) triggerThreshold = mBackPanelController.params.staticTriggerThreshold } @@ -103,6 +108,7 @@ class BackPanelControllerTest : SysuiTestCase() { assertThat(mBackPanelController.currentState) .isEqualTo(BackPanelController.GestureState.GONE) + verify(interactionJankMonitor, never()).begin(any()) } @Test @@ -110,23 +116,37 @@ class BackPanelControllerTest : SysuiTestCase() { startTouch() // Move once to cross the touch slop continueTouch(START_X + touchSlop.toFloat() + 1) + assertThat(mBackPanelController.currentState) + .isEqualTo(BackPanelController.GestureState.ENTRY) + verify(interactionJankMonitor).cancel(Cuj.CUJ_BACK_PANEL_ARROW) + verify(interactionJankMonitor) + .begin(mBackPanelController.getBackPanelView(), Cuj.CUJ_BACK_PANEL_ARROW) // Move again to cross the back trigger threshold continueTouch(START_X + touchSlop + triggerThreshold + 1) // Wait threshold duration and hold touch past trigger threshold - Thread.sleep((MAX_DURATION_ENTRY_BEFORE_ACTIVE_ANIMATION + 1).toLong()) + moveTimeForward((MAX_DURATION_ENTRY_BEFORE_ACTIVE_ANIMATION + 1).toLong()) continueTouch(START_X + touchSlop + triggerThreshold + 1) assertThat(mBackPanelController.currentState) .isEqualTo(BackPanelController.GestureState.ACTIVE) verify(backCallback).setTriggerBack(true) - testableLooper.moveTimeForward(100) - testableLooper.processAllMessages() + moveTimeForward(100) verify(vibratorHelper) .performHapticFeedback(any(), eq(HapticFeedbackConstants.GESTURE_THRESHOLD_ACTIVATE)) finishTouchActionUp(START_X + touchSlop + triggerThreshold + 1) assertThat(mBackPanelController.currentState) .isEqualTo(BackPanelController.GestureState.COMMITTED) verify(backCallback).triggerBack() + + // Because the Handler that is typically used for transitioning the arrow state from + // COMMITTED to GONE is used as an animation-end-listener on a SpringAnimation, + // there is no way to meaningfully test that the state becomes GONE and that the tracked + // jank interaction is ended. So instead, manually trigger the failsafe, which does + // the same thing: + mBackPanelController.failsafeRunnable.run() + assertThat(mBackPanelController.currentState) + .isEqualTo(BackPanelController.GestureState.GONE) + verify(interactionJankMonitor).end(Cuj.CUJ_BACK_PANEL_ARROW) } @Test @@ -134,19 +154,22 @@ class BackPanelControllerTest : SysuiTestCase() { startTouch() // Move once to cross the touch slop continueTouch(START_X + touchSlop.toFloat() + 1) + assertThat(mBackPanelController.currentState) + .isEqualTo(BackPanelController.GestureState.ENTRY) // Move again to cross the back trigger threshold continueTouch( START_X + touchSlop + triggerThreshold - mBackPanelController.params.deactivationTriggerThreshold ) // Wait threshold duration and hold touch before trigger threshold - Thread.sleep((MAX_DURATION_ENTRY_BEFORE_ACTIVE_ANIMATION + 1).toLong()) + moveTimeForward((MAX_DURATION_ENTRY_BEFORE_ACTIVE_ANIMATION + 1).toLong()) continueTouch( START_X + touchSlop + triggerThreshold - mBackPanelController.params.deactivationTriggerThreshold ) clearInvocations(backCallback) - Thread.sleep(MIN_DURATION_ACTIVE_BEFORE_INACTIVE_ANIMATION) + moveTimeForward(MIN_DURATION_ACTIVE_BEFORE_INACTIVE_ANIMATION) + // Move in the opposite direction to cross the deactivation threshold and cancel back continueTouch(START_X) @@ -175,4 +198,10 @@ class BackPanelControllerTest : SysuiTestCase() { private fun createMotionEvent(action: Int, x: Float, y: Float): MotionEvent { return MotionEvent.obtain(0L, 0L, action, x, y, 0) } + + private fun moveTimeForward(millis: Long) { + systemClock.advanceTime(millis) + testableLooper.moveTimeForward(millis) + testableLooper.processAllMessages() + } } |