Merge "[Unfold transition] Update latency tracker to listen for animation start" into tm-qpr-dev

This commit is contained in:
Nick Chameyev
2022-12-19 11:20:03 +00:00
committed by Android (Google) Code Review
4 changed files with 185 additions and 11 deletions

View File

@@ -17,6 +17,7 @@ package com.android.systemui.keyguard
import com.android.systemui.unfold.updates.screen.ScreenStatusProvider
import com.android.systemui.unfold.updates.screen.ScreenStatusProvider.ScreenListener
import com.android.systemui.util.traceSection
import javax.inject.Inject
import javax.inject.Singleton
@@ -39,14 +40,22 @@ class LifecycleScreenStatusProvider @Inject constructor(screenLifecycle: ScreenL
}
override fun onScreenTurnedOn() {
listeners.forEach(ScreenListener::onScreenTurnedOn)
traceSection("$TRACE_TAG#onScreenTurnedOn") {
listeners.forEach(ScreenListener::onScreenTurnedOn)
}
}
override fun onScreenTurningOff() {
listeners.forEach(ScreenListener::onScreenTurningOff)
traceSection("$TRACE_TAG#onScreenTurningOff") {
listeners.forEach(ScreenListener::onScreenTurningOff)
}
}
override fun onScreenTurningOn() {
listeners.forEach(ScreenListener::onScreenTurningOn)
traceSection("$TRACE_TAG#onScreenTurningOn") {
listeners.forEach(ScreenListener::onScreenTurningOn)
}
}
}
private const val TRACE_TAG = "LifecycleScreenStatusProvider"

View File

@@ -16,12 +16,18 @@
package com.android.systemui.unfold
import android.content.ContentResolver
import android.content.Context
import android.hardware.devicestate.DeviceStateManager
import android.util.Log
import com.android.internal.util.LatencyTracker
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.UiBackground
import com.android.systemui.keyguard.ScreenLifecycle
import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
import com.android.systemui.unfold.util.ScaleAwareTransitionProgressProvider.Companion.areAnimationsEnabled
import com.android.systemui.util.Compile
import java.util.Optional
import java.util.concurrent.Executor
import javax.inject.Inject
@@ -41,17 +47,19 @@ class UnfoldLatencyTracker
constructor(
private val latencyTracker: LatencyTracker,
private val deviceStateManager: DeviceStateManager,
private val transitionProgressProvider: Optional<UnfoldTransitionProgressProvider>,
@UiBackground private val uiBgExecutor: Executor,
private val context: Context,
private val contentResolver: ContentResolver,
private val screenLifecycle: ScreenLifecycle
) : ScreenLifecycle.Observer {
) : ScreenLifecycle.Observer, TransitionProgressListener {
private var folded: Boolean? = null
private var isTransitionEnabled: Boolean? = null
private val foldStateListener = FoldStateListener(context)
private val isFoldable: Boolean
get() =
context
.resources
context.resources
.getIntArray(com.android.internal.R.array.config_foldedDeviceStates)
.isNotEmpty()
@@ -62,6 +70,11 @@ constructor(
}
deviceStateManager.registerCallback(uiBgExecutor, foldStateListener)
screenLifecycle.addObserver(this)
if (transitionProgressProvider.isPresent) {
// Might not be present if the device is not a foldable device or unfold transition
// is disabled in the device configuration
transitionProgressProvider.get().addCallback(this)
}
}
/**
@@ -71,16 +84,72 @@ constructor(
* end action event only if we previously received a fold state.
*/
override fun onScreenTurnedOn() {
if (folded == false) {
if (DEBUG) {
Log.d(
TAG,
"onScreenTurnedOn: folded = $folded, isTransitionEnabled = $isTransitionEnabled"
)
}
// We use onScreenTurnedOn event to finish tracking only if we are not playing
// the unfold animation (e.g. it could be disabled because of battery saver).
// When animation is enabled finishing of the tracking will be done in onTransitionStarted.
if (folded == false && isTransitionEnabled == false) {
latencyTracker.onActionEnd(LatencyTracker.ACTION_SWITCH_DISPLAY_UNFOLD)
if (DEBUG) {
Log.d(TAG, "onScreenTurnedOn: ending ACTION_SWITCH_DISPLAY_UNFOLD")
}
}
}
/**
* This callback is used to end the metric when the unfold animation is enabled because it could
* add an additional delay to synchronize with launcher.
*/
override fun onTransitionStarted() {
if (DEBUG) {
Log.d(
TAG,
"onTransitionStarted: folded = $folded, isTransitionEnabled = $isTransitionEnabled"
)
}
if (folded == false && isTransitionEnabled == true) {
latencyTracker.onActionEnd(LatencyTracker.ACTION_SWITCH_DISPLAY_UNFOLD)
if (DEBUG) {
Log.d(TAG, "onTransitionStarted: ending ACTION_SWITCH_DISPLAY_UNFOLD")
}
}
}
private fun onFoldEvent(folded: Boolean) {
if (this.folded != folded) {
val oldFolded = this.folded
if (oldFolded != folded) {
this.folded = folded
if (!folded) { // unfolding started
if (DEBUG) {
Log.d(TAG, "Received onFoldEvent = $folded")
}
// Do not start tracking when oldFolded is null, this means that this is the first
// onFoldEvent after booting the device or starting SystemUI and not actual folding or
// unfolding the device.
if (oldFolded != null && !folded) {
// Unfolding started
latencyTracker.onActionStart(LatencyTracker.ACTION_SWITCH_DISPLAY_UNFOLD)
isTransitionEnabled =
transitionProgressProvider.isPresent && contentResolver.areAnimationsEnabled()
if (DEBUG) {
Log.d(
TAG,
"Starting ACTION_SWITCH_DISPLAY_UNFOLD, " +
"isTransitionEnabled = $isTransitionEnabled"
)
}
}
}
}
@@ -88,3 +157,6 @@ constructor(
private inner class FoldStateListener(context: Context) :
DeviceStateManager.FoldStateListener(context, { onFoldEvent(it) })
}
private const val TAG = "UnfoldLatencyTracker"
private val DEBUG = Compile.IS_DEBUG && Log.isLoggable(TAG, Log.VERBOSE)

View File

@@ -18,6 +18,7 @@ package com.android.systemui.unfold
import android.hardware.devicestate.DeviceStateManager
import android.hardware.devicestate.DeviceStateManager.FoldStateListener
import android.provider.Settings
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.internal.util.LatencyTracker
@@ -32,9 +33,11 @@ import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.Captor
import org.mockito.Mock
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions
import org.mockito.MockitoAnnotations
import java.util.Optional
@RunWith(AndroidTestingRunner::class)
@SmallTest
@@ -59,14 +62,18 @@ class UnfoldLatencyTrackerTest : SysuiTestCase() {
private lateinit var unfoldLatencyTracker: UnfoldLatencyTracker
private val transitionProgressProvider = TestUnfoldTransitionProvider()
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
unfoldLatencyTracker = UnfoldLatencyTracker(
latencyTracker,
deviceStateManager,
Optional.of(transitionProgressProvider),
context.mainExecutor,
context,
context.contentResolver,
screenLifecycle
).apply { init() }
deviceStates = FoldableTestUtils.findDeviceStates(context)
@@ -76,8 +83,11 @@ class UnfoldLatencyTrackerTest : SysuiTestCase() {
}
@Test
fun unfold_eventPropagated() {
fun unfold_startedFolded_animationsDisabled_eventPropagatedOnScreenTurnedOnEvent() {
setAnimationsEnabled(false)
sendFoldEvent(folded = true)
sendFoldEvent(folded = false)
sendScreenTurnedOnEvent()
verify(latencyTracker).onActionStart(any())
@@ -85,13 +95,76 @@ class UnfoldLatencyTrackerTest : SysuiTestCase() {
}
@Test
fun fold_eventNotPropagated() {
fun unfold_startedFolded_animationsEnabledOnScreenTurnedOn_eventNotFinished() {
setAnimationsEnabled(true)
sendFoldEvent(folded = true)
sendFoldEvent(folded = false)
sendScreenTurnedOnEvent()
verify(latencyTracker).onActionStart(any())
verify(latencyTracker, never()).onActionEnd(any())
}
@Test
fun unfold_firstFoldEventAnimationsEnabledOnScreenTurnedOnAndTransitionStarted_eventNotPropagated() {
setAnimationsEnabled(true)
sendFoldEvent(folded = false)
sendScreenTurnedOnEvent()
transitionProgressProvider.onTransitionStarted()
verifyNoMoreInteractions(latencyTracker)
}
@Test
fun unfold_secondFoldEventAnimationsEnabledOnScreenTurnedOnAndTransitionStarted_eventPropagated() {
setAnimationsEnabled(true)
sendFoldEvent(folded = true)
sendFoldEvent(folded = false)
sendScreenTurnedOnEvent()
transitionProgressProvider.onTransitionStarted()
verify(latencyTracker).onActionStart(any())
verify(latencyTracker).onActionEnd(any())
}
@Test
fun unfold_unfoldFoldUnfoldAnimationsEnabledOnScreenTurnedOnAndTransitionStarted_eventPropagated() {
setAnimationsEnabled(true)
sendFoldEvent(folded = false)
sendFoldEvent(folded = true)
sendFoldEvent(folded = false)
sendScreenTurnedOnEvent()
transitionProgressProvider.onTransitionStarted()
verify(latencyTracker).onActionStart(any())
verify(latencyTracker).onActionEnd(any())
}
@Test
fun fold_animationsDisabled_screenTurnedOn_eventNotPropagated() {
setAnimationsEnabled(false)
sendFoldEvent(folded = true)
sendScreenTurnedOnEvent() // outer display on.
verifyNoMoreInteractions(latencyTracker)
}
@Test
fun fold_animationsEnabled_screenTurnedOn_eventNotPropagated() {
setAnimationsEnabled(true)
sendFoldEvent(folded = true)
sendScreenTurnedOnEvent() // outer display on.
transitionProgressProvider.onTransitionStarted()
verifyNoMoreInteractions(latencyTracker)
}
@Test
fun onScreenTurnedOn_stateNeverSet_eventNotPropagated() {
sendScreenTurnedOnEvent()
@@ -107,4 +180,20 @@ class UnfoldLatencyTrackerTest : SysuiTestCase() {
private fun sendScreenTurnedOnEvent() {
screenLifecycleCaptor.value.onScreenTurnedOn()
}
private fun setAnimationsEnabled(enabled: Boolean) {
val durationScale =
if (enabled) {
1f
} else {
0f
}
// It uses [TestableSettingsProvider] and it will be cleared after the test
Settings.Global.putString(
context.contentResolver,
Settings.Global.ANIMATOR_DURATION_SCALE,
durationScale.toString()
)
}
}

View File

@@ -16,6 +16,7 @@
package com.android.systemui.unfold.progress
import android.os.Trace
import android.os.Trace.TRACE_TAG_APP
import android.util.Log
import androidx.dynamicanimation.animation.DynamicAnimation
import androidx.dynamicanimation.animation.FloatPropertyCompat
@@ -157,7 +158,10 @@ class PhysicsBasedUnfoldTransitionProgressProvider(
}
private fun onStartTransition() {
Trace.beginSection( "$TAG#onStartTransition")
listeners.forEach { it.onTransitionStarted() }
Trace.endSection()
isTransitionRunning = true
if (DEBUG) {