Merge "[Unfold transition] Update latency tracker to listen for animation start" into tm-qpr-dev am: 596e3f9025
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/20637217 Change-Id: Ie5445ece5ea5d0c19d7f0e37306a6f8cb297ad99 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -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
|
||||||
import com.android.systemui.unfold.updates.screen.ScreenStatusProvider.ScreenListener
|
import com.android.systemui.unfold.updates.screen.ScreenStatusProvider.ScreenListener
|
||||||
|
import com.android.systemui.util.traceSection
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@@ -39,14 +40,22 @@ class LifecycleScreenStatusProvider @Inject constructor(screenLifecycle: ScreenL
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onScreenTurnedOn() {
|
override fun onScreenTurnedOn() {
|
||||||
listeners.forEach(ScreenListener::onScreenTurnedOn)
|
traceSection("$TRACE_TAG#onScreenTurnedOn") {
|
||||||
|
listeners.forEach(ScreenListener::onScreenTurnedOn)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onScreenTurningOff() {
|
override fun onScreenTurningOff() {
|
||||||
listeners.forEach(ScreenListener::onScreenTurningOff)
|
traceSection("$TRACE_TAG#onScreenTurningOff") {
|
||||||
|
listeners.forEach(ScreenListener::onScreenTurningOff)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onScreenTurningOn() {
|
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
|
package com.android.systemui.unfold
|
||||||
|
|
||||||
|
import android.content.ContentResolver
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.hardware.devicestate.DeviceStateManager
|
import android.hardware.devicestate.DeviceStateManager
|
||||||
|
import android.util.Log
|
||||||
import com.android.internal.util.LatencyTracker
|
import com.android.internal.util.LatencyTracker
|
||||||
import com.android.systemui.dagger.SysUISingleton
|
import com.android.systemui.dagger.SysUISingleton
|
||||||
import com.android.systemui.dagger.qualifiers.UiBackground
|
import com.android.systemui.dagger.qualifiers.UiBackground
|
||||||
import com.android.systemui.keyguard.ScreenLifecycle
|
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 java.util.concurrent.Executor
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@@ -41,17 +47,19 @@ class UnfoldLatencyTracker
|
|||||||
constructor(
|
constructor(
|
||||||
private val latencyTracker: LatencyTracker,
|
private val latencyTracker: LatencyTracker,
|
||||||
private val deviceStateManager: DeviceStateManager,
|
private val deviceStateManager: DeviceStateManager,
|
||||||
|
private val transitionProgressProvider: Optional<UnfoldTransitionProgressProvider>,
|
||||||
@UiBackground private val uiBgExecutor: Executor,
|
@UiBackground private val uiBgExecutor: Executor,
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
|
private val contentResolver: ContentResolver,
|
||||||
private val screenLifecycle: ScreenLifecycle
|
private val screenLifecycle: ScreenLifecycle
|
||||||
) : ScreenLifecycle.Observer {
|
) : ScreenLifecycle.Observer, TransitionProgressListener {
|
||||||
|
|
||||||
private var folded: Boolean? = null
|
private var folded: Boolean? = null
|
||||||
|
private var isTransitionEnabled: Boolean? = null
|
||||||
private val foldStateListener = FoldStateListener(context)
|
private val foldStateListener = FoldStateListener(context)
|
||||||
private val isFoldable: Boolean
|
private val isFoldable: Boolean
|
||||||
get() =
|
get() =
|
||||||
context
|
context.resources
|
||||||
.resources
|
|
||||||
.getIntArray(com.android.internal.R.array.config_foldedDeviceStates)
|
.getIntArray(com.android.internal.R.array.config_foldedDeviceStates)
|
||||||
.isNotEmpty()
|
.isNotEmpty()
|
||||||
|
|
||||||
@@ -62,6 +70,11 @@ constructor(
|
|||||||
}
|
}
|
||||||
deviceStateManager.registerCallback(uiBgExecutor, foldStateListener)
|
deviceStateManager.registerCallback(uiBgExecutor, foldStateListener)
|
||||||
screenLifecycle.addObserver(this)
|
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.
|
* end action event only if we previously received a fold state.
|
||||||
*/
|
*/
|
||||||
override fun onScreenTurnedOn() {
|
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)
|
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) {
|
private fun onFoldEvent(folded: Boolean) {
|
||||||
if (this.folded != folded) {
|
val oldFolded = this.folded
|
||||||
|
|
||||||
|
if (oldFolded != folded) {
|
||||||
this.folded = 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)
|
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) :
|
private inner class FoldStateListener(context: Context) :
|
||||||
DeviceStateManager.FoldStateListener(context, { onFoldEvent(it) })
|
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
|
||||||
import android.hardware.devicestate.DeviceStateManager.FoldStateListener
|
import android.hardware.devicestate.DeviceStateManager.FoldStateListener
|
||||||
|
import android.provider.Settings
|
||||||
import android.testing.AndroidTestingRunner
|
import android.testing.AndroidTestingRunner
|
||||||
import androidx.test.filters.SmallTest
|
import androidx.test.filters.SmallTest
|
||||||
import com.android.internal.util.LatencyTracker
|
import com.android.internal.util.LatencyTracker
|
||||||
@@ -32,9 +33,11 @@ import org.junit.runner.RunWith
|
|||||||
import org.mockito.ArgumentCaptor
|
import org.mockito.ArgumentCaptor
|
||||||
import org.mockito.Captor
|
import org.mockito.Captor
|
||||||
import org.mockito.Mock
|
import org.mockito.Mock
|
||||||
|
import org.mockito.Mockito.never
|
||||||
import org.mockito.Mockito.verify
|
import org.mockito.Mockito.verify
|
||||||
import org.mockito.Mockito.verifyNoMoreInteractions
|
import org.mockito.Mockito.verifyNoMoreInteractions
|
||||||
import org.mockito.MockitoAnnotations
|
import org.mockito.MockitoAnnotations
|
||||||
|
import java.util.Optional
|
||||||
|
|
||||||
@RunWith(AndroidTestingRunner::class)
|
@RunWith(AndroidTestingRunner::class)
|
||||||
@SmallTest
|
@SmallTest
|
||||||
@@ -59,14 +62,18 @@ class UnfoldLatencyTrackerTest : SysuiTestCase() {
|
|||||||
|
|
||||||
private lateinit var unfoldLatencyTracker: UnfoldLatencyTracker
|
private lateinit var unfoldLatencyTracker: UnfoldLatencyTracker
|
||||||
|
|
||||||
|
private val transitionProgressProvider = TestUnfoldTransitionProvider()
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun setUp() {
|
fun setUp() {
|
||||||
MockitoAnnotations.initMocks(this)
|
MockitoAnnotations.initMocks(this)
|
||||||
unfoldLatencyTracker = UnfoldLatencyTracker(
|
unfoldLatencyTracker = UnfoldLatencyTracker(
|
||||||
latencyTracker,
|
latencyTracker,
|
||||||
deviceStateManager,
|
deviceStateManager,
|
||||||
|
Optional.of(transitionProgressProvider),
|
||||||
context.mainExecutor,
|
context.mainExecutor,
|
||||||
context,
|
context,
|
||||||
|
context.contentResolver,
|
||||||
screenLifecycle
|
screenLifecycle
|
||||||
).apply { init() }
|
).apply { init() }
|
||||||
deviceStates = FoldableTestUtils.findDeviceStates(context)
|
deviceStates = FoldableTestUtils.findDeviceStates(context)
|
||||||
@@ -76,8 +83,11 @@ class UnfoldLatencyTrackerTest : SysuiTestCase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun unfold_eventPropagated() {
|
fun unfold_startedFolded_animationsDisabled_eventPropagatedOnScreenTurnedOnEvent() {
|
||||||
|
setAnimationsEnabled(false)
|
||||||
|
sendFoldEvent(folded = true)
|
||||||
sendFoldEvent(folded = false)
|
sendFoldEvent(folded = false)
|
||||||
|
|
||||||
sendScreenTurnedOnEvent()
|
sendScreenTurnedOnEvent()
|
||||||
|
|
||||||
verify(latencyTracker).onActionStart(any())
|
verify(latencyTracker).onActionStart(any())
|
||||||
@@ -85,13 +95,76 @@ class UnfoldLatencyTrackerTest : SysuiTestCase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun fold_eventNotPropagated() {
|
fun unfold_startedFolded_animationsEnabledOnScreenTurnedOn_eventNotFinished() {
|
||||||
|
setAnimationsEnabled(true)
|
||||||
sendFoldEvent(folded = 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.
|
sendScreenTurnedOnEvent() // outer display on.
|
||||||
|
|
||||||
verifyNoMoreInteractions(latencyTracker)
|
verifyNoMoreInteractions(latencyTracker)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun fold_animationsEnabled_screenTurnedOn_eventNotPropagated() {
|
||||||
|
setAnimationsEnabled(true)
|
||||||
|
sendFoldEvent(folded = true)
|
||||||
|
|
||||||
|
sendScreenTurnedOnEvent() // outer display on.
|
||||||
|
transitionProgressProvider.onTransitionStarted()
|
||||||
|
|
||||||
|
verifyNoMoreInteractions(latencyTracker)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun onScreenTurnedOn_stateNeverSet_eventNotPropagated() {
|
fun onScreenTurnedOn_stateNeverSet_eventNotPropagated() {
|
||||||
sendScreenTurnedOnEvent()
|
sendScreenTurnedOnEvent()
|
||||||
@@ -107,4 +180,20 @@ class UnfoldLatencyTrackerTest : SysuiTestCase() {
|
|||||||
private fun sendScreenTurnedOnEvent() {
|
private fun sendScreenTurnedOnEvent() {
|
||||||
screenLifecycleCaptor.value.onScreenTurnedOn()
|
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
|
package com.android.systemui.unfold.progress
|
||||||
|
|
||||||
import android.os.Trace
|
import android.os.Trace
|
||||||
|
import android.os.Trace.TRACE_TAG_APP
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.dynamicanimation.animation.DynamicAnimation
|
import androidx.dynamicanimation.animation.DynamicAnimation
|
||||||
import androidx.dynamicanimation.animation.FloatPropertyCompat
|
import androidx.dynamicanimation.animation.FloatPropertyCompat
|
||||||
@@ -157,7 +158,10 @@ class PhysicsBasedUnfoldTransitionProgressProvider(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun onStartTransition() {
|
private fun onStartTransition() {
|
||||||
|
Trace.beginSection( "$TAG#onStartTransition")
|
||||||
listeners.forEach { it.onTransitionStarted() }
|
listeners.forEach { it.onTransitionStarted() }
|
||||||
|
Trace.endSection()
|
||||||
|
|
||||||
isTransitionRunning = true
|
isTransitionRunning = true
|
||||||
|
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
|
|||||||
Reference in New Issue
Block a user