Merge "[Unfold transition] Update latency tracker to listen for animation start" into tm-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
596e3f9025
@@ -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"
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user