[Unfold animation] Get animation scale from content provider

ValueAnimator#areAnimationsEnabled() method does not
reflect the latest state of the animation scale
at the time when content provider emitted an update.
It led to a bug after disabling and enabling
animations: we added the unfold overlay in the
 UnfoldLightRevealOverlayAnimation (as animations
enabled) but didn't remove it because the transition
progress provider never reported animation start,
progress and finish events.

Changed to use the content provider to get
the latest state of the animation scale.

Bug: 256072006
Test: manual fold/unfolds after enabling/disabling talkback
Test: com.android.systemui.unfold.util.ScaleAwareUnfoldProgressProviderTest
Change-Id: If5d982791b9f8103ecfd8db44e24d2486560d4f5
This commit is contained in:
Nick Chameyev
2022-11-17 12:32:42 +00:00
parent c3de18645f
commit 982c56f661
3 changed files with 53 additions and 34 deletions

View File

@@ -15,7 +15,7 @@
*/
package com.android.systemui.unfold
import android.animation.ValueAnimator
import android.content.ContentResolver
import android.content.Context
import android.graphics.PixelFormat
import android.hardware.devicestate.DeviceStateManager
@@ -39,6 +39,7 @@ import com.android.systemui.statusbar.LightRevealScrim
import com.android.systemui.statusbar.LinearLightRevealEffect
import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
import com.android.systemui.unfold.updates.RotationChangeProvider
import com.android.systemui.unfold.util.ScaleAwareTransitionProgressProvider.Companion.areAnimationsEnabled
import com.android.systemui.util.traceSection
import com.android.wm.shell.displayareahelper.DisplayAreaHelper
import java.util.Optional
@@ -52,6 +53,7 @@ class UnfoldLightRevealOverlayAnimation
constructor(
private val context: Context,
private val deviceStateManager: DeviceStateManager,
private val contentResolver: ContentResolver,
private val displayManager: DisplayManager,
private val unfoldTransitionProgressProvider: UnfoldTransitionProgressProvider,
private val displayAreaHelper: Optional<DisplayAreaHelper>,
@@ -117,7 +119,7 @@ constructor(
Trace.beginSection("UnfoldLightRevealOverlayAnimation#onScreenTurningOn")
try {
// Add the view only if we are unfolding and this is the first screen on
if (!isFolded && !isUnfoldHandled && ValueAnimator.areAnimatorsEnabled()) {
if (!isFolded && !isUnfoldHandled && contentResolver.areAnimationsEnabled()) {
addView(onOverlayReady)
isUnfoldHandled = true
} else {
@@ -162,11 +164,10 @@ constructor(
// blocker (turn on the brightness) only when the content is actually visible as it
// might be presented only in the next frame.
// See b/197538198
transaction
.setFrameTimelineVsync(vsyncId)
.apply()
transaction.setFrameTimelineVsync(vsyncId).apply()
transaction.setFrameTimelineVsync(vsyncId + 1)
transaction
.setFrameTimelineVsync(vsyncId + 1)
.addTransactionCommittedListener(backgroundExecutor) {
Trace.endAsyncSection("UnfoldLightRevealOverlayAnimation#relayout", 0)
callback.run()
@@ -218,8 +219,7 @@ constructor(
}
private fun getUnfoldedDisplayInfo(): DisplayInfo =
displayManager
.displays
displayManager.displays
.asSequence()
.map { DisplayInfo().apply { it.getDisplayInfo(this) } }
.filter { it.type == Display.TYPE_INTERNAL }
@@ -266,5 +266,6 @@ constructor(
isUnfoldHandled = false
}
this.isFolded = isFolded
})
}
)
}

View File

@@ -15,14 +15,13 @@
*/
package com.android.systemui.unfold.util
import android.animation.ValueAnimator
import android.content.ContentResolver
import android.database.ContentObserver
import android.provider.Settings
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.unfold.TestUnfoldTransitionProvider
import com.android.systemui.unfold.UnfoldTransitionProgressProvider
import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
import com.android.systemui.util.mockito.any
import org.junit.Before
@@ -30,6 +29,7 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.Mock
import org.mockito.Mockito.spy
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions
import org.mockito.MockitoAnnotations
@@ -38,30 +38,25 @@ import org.mockito.MockitoAnnotations
@SmallTest
class ScaleAwareUnfoldProgressProviderTest : SysuiTestCase() {
@Mock
lateinit var contentResolver: ContentResolver
@Mock
lateinit var sinkProvider: TransitionProgressListener
@Mock lateinit var sinkProvider: TransitionProgressListener
private val sourceProvider = TestUnfoldTransitionProvider()
lateinit var progressProvider: ScaleAwareTransitionProgressProvider
private lateinit var contentResolver: ContentResolver
private lateinit var progressProvider: ScaleAwareTransitionProgressProvider
private val animatorDurationScaleListenerCaptor =
ArgumentCaptor.forClass(ContentObserver::class.java)
ArgumentCaptor.forClass(ContentObserver::class.java)
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
contentResolver = spy(context.contentResolver)
progressProvider = ScaleAwareTransitionProgressProvider(
sourceProvider,
contentResolver
)
progressProvider = ScaleAwareTransitionProgressProvider(sourceProvider, contentResolver)
verify(contentResolver).registerContentObserver(any(), any(),
animatorDurationScaleListenerCaptor.capture())
verify(contentResolver)
.registerContentObserver(any(), any(), animatorDurationScaleListenerCaptor.capture())
progressProvider.addCallback(sinkProvider)
}
@@ -121,12 +116,20 @@ class ScaleAwareUnfoldProgressProviderTest : SysuiTestCase() {
}
private fun setAnimationsEnabled(enabled: Boolean) {
val durationScale = if (enabled) {
1f
} else {
0f
}
ValueAnimator.setDurationScale(durationScale)
val durationScale =
if (enabled) {
1f
} else {
0f
}
// It uses [TestableSettingsProvider] and it will be cleared after the test
Settings.Global.putString(
contentResolver,
Settings.Global.ANIMATOR_DURATION_SCALE,
durationScale.toString()
)
animatorDurationScaleListenerCaptor.value.dispatchChange(/* selfChange= */false)
}
}

View File

@@ -14,7 +14,6 @@
*/
package com.android.systemui.unfold.util
import android.animation.ValueAnimator
import android.content.ContentResolver
import android.database.ContentObserver
import android.provider.Settings
@@ -46,13 +45,15 @@ constructor(
contentResolver.registerContentObserver(
Settings.Global.getUriFor(Settings.Global.ANIMATOR_DURATION_SCALE),
/* notifyForDescendants= */ false,
animatorDurationScaleObserver)
animatorDurationScaleObserver
)
onAnimatorScaleChanged()
}
private fun onAnimatorScaleChanged() {
val animationsEnabled = ValueAnimator.areAnimatorsEnabled()
scopedUnfoldTransitionProgressProvider.setReadyToHandleTransition(animationsEnabled)
scopedUnfoldTransitionProgressProvider.setReadyToHandleTransition(
contentResolver.areAnimationsEnabled()
)
}
override fun addCallback(listener: TransitionProgressListener) {
@@ -74,4 +75,18 @@ constructor(
progressProvider: UnfoldTransitionProgressProvider
): ScaleAwareTransitionProgressProvider
}
companion object {
fun ContentResolver.areAnimationsEnabled(): Boolean {
val animationScale =
Settings.Global.getStringForUser(
this,
Settings.Global.ANIMATOR_DURATION_SCALE,
this.userId
)
?.toFloatOrNull()
?: 1f
return animationScale != 0f
}
}
}