Merge "Disable unfold animation when animations disabled" into sc-v2-dev

This commit is contained in:
Nicolò Mazzucato
2021-12-03 13:24:07 +00:00
committed by Android (Google) Code Review
5 changed files with 197 additions and 3 deletions

View File

@@ -26,6 +26,7 @@ import com.android.systemui.unfold.config.ResourceUnfoldTransitionConfig
import com.android.systemui.unfold.config.UnfoldTransitionConfig import com.android.systemui.unfold.config.UnfoldTransitionConfig
import com.android.systemui.unfold.progress.FixedTimingTransitionProgressProvider import com.android.systemui.unfold.progress.FixedTimingTransitionProgressProvider
import com.android.systemui.unfold.progress.PhysicsBasedUnfoldTransitionProgressProvider import com.android.systemui.unfold.progress.PhysicsBasedUnfoldTransitionProgressProvider
import com.android.systemui.unfold.util.ScaleAwareTransitionProgressProvider
import com.android.systemui.unfold.updates.DeviceFoldStateProvider import com.android.systemui.unfold.updates.DeviceFoldStateProvider
import com.android.systemui.unfold.updates.hinge.EmptyHingeAngleProvider import com.android.systemui.unfold.updates.hinge.EmptyHingeAngleProvider
import com.android.systemui.unfold.updates.hinge.HingeSensorAngleProvider import com.android.systemui.unfold.updates.hinge.HingeSensorAngleProvider
@@ -62,7 +63,7 @@ fun createUnfoldTransitionProgressProvider(
mainExecutor mainExecutor
) )
return if (config.isHingeAngleEnabled) { val unfoldTransitionProgressProvider = if (config.isHingeAngleEnabled) {
PhysicsBasedUnfoldTransitionProgressProvider( PhysicsBasedUnfoldTransitionProgressProvider(
mainHandler, mainHandler,
foldStateProvider foldStateProvider
@@ -70,6 +71,10 @@ fun createUnfoldTransitionProgressProvider(
} else { } else {
FixedTimingTransitionProgressProvider(foldStateProvider) FixedTimingTransitionProgressProvider(foldStateProvider)
} }
return ScaleAwareTransitionProgressProvider(
unfoldTransitionProgressProvider,
context.contentResolver
)
} }
fun createConfig(context: Context): UnfoldTransitionConfig = fun createConfig(context: Context): UnfoldTransitionConfig =

View File

@@ -2,7 +2,6 @@ package com.android.systemui.unfold.util
import android.content.Context import android.content.Context
import android.os.RemoteException import android.os.RemoteException
import android.util.Log
import android.view.IRotationWatcher import android.view.IRotationWatcher
import android.view.IWindowManager import android.view.IWindowManager
import android.view.Surface import android.view.Surface

View File

@@ -0,0 +1,50 @@
package com.android.systemui.unfold.util
import android.animation.ValueAnimator
import android.content.ContentResolver
import android.database.ContentObserver
import android.provider.Settings
import com.android.systemui.unfold.UnfoldTransitionProgressProvider
import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
/** Wraps [UnfoldTransitionProgressProvider] to disable transitions when animations are disabled. */
class ScaleAwareTransitionProgressProvider(
unfoldTransitionProgressProvider: UnfoldTransitionProgressProvider,
private val contentResolver: ContentResolver
) : UnfoldTransitionProgressProvider {
private val scopedUnfoldTransitionProgressProvider =
ScopedUnfoldTransitionProgressProvider(unfoldTransitionProgressProvider)
private val animatorDurationScaleObserver = object : ContentObserver(null) {
override fun onChange(selfChange: Boolean) {
onAnimatorScaleChanged()
}
}
init {
contentResolver.registerContentObserver(
Settings.Global.getUriFor(Settings.Global.ANIMATOR_DURATION_SCALE),
/* notifyForDescendants= */ false,
animatorDurationScaleObserver)
onAnimatorScaleChanged()
}
private fun onAnimatorScaleChanged() {
val animationsEnabled = ValueAnimator.areAnimatorsEnabled()
scopedUnfoldTransitionProgressProvider.setReadyToHandleTransition(animationsEnabled)
}
override fun addCallback(listener: TransitionProgressListener) {
scopedUnfoldTransitionProgressProvider.addCallback(listener)
}
override fun removeCallback(listener: TransitionProgressListener) {
scopedUnfoldTransitionProgressProvider.removeCallback(listener)
}
override fun destroy() {
contentResolver.unregisterContentObserver(animatorDurationScaleObserver)
scopedUnfoldTransitionProgressProvider.destroy()
}
}

View File

@@ -15,6 +15,7 @@
*/ */
package com.android.systemui.unfold package com.android.systemui.unfold
import android.animation.ValueAnimator
import android.content.Context import android.content.Context
import android.graphics.PixelFormat import android.graphics.PixelFormat
import android.hardware.devicestate.DeviceStateManager import android.hardware.devicestate.DeviceStateManager
@@ -111,7 +112,7 @@ class UnfoldLightRevealOverlayAnimation @Inject constructor(
Trace.beginSection("UnfoldLightRevealOverlayAnimation#onScreenTurningOn") Trace.beginSection("UnfoldLightRevealOverlayAnimation#onScreenTurningOn")
try { try {
// Add the view only if we are unfolding and this is the first screen on // Add the view only if we are unfolding and this is the first screen on
if (!isFolded && !isUnfoldHandled) { if (!isFolded && !isUnfoldHandled && ValueAnimator.areAnimatorsEnabled()) {
addView(onOverlayReady) addView(onOverlayReady)
isUnfoldHandled = true isUnfoldHandled = true
} else { } else {

View File

@@ -0,0 +1,139 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.unfold.util
import android.animation.ValueAnimator
import android.content.ContentResolver
import android.database.ContentObserver
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.unfold.UnfoldTransitionProgressProvider
import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
import com.android.systemui.util.mockito.any
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.Mock
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions
import org.mockito.MockitoAnnotations
@RunWith(AndroidTestingRunner::class)
@SmallTest
class ScaleAwareUnfoldProgressProviderTest : SysuiTestCase() {
@Mock
lateinit var contentResolver: ContentResolver
@Mock
lateinit var sourceProvider: UnfoldTransitionProgressProvider
@Mock
lateinit var sinkProvider: TransitionProgressListener
lateinit var progressProvider: ScaleAwareTransitionProgressProvider
private val sourceProviderListenerCaptor =
ArgumentCaptor.forClass(TransitionProgressListener::class.java)
private val animatorDurationScaleListenerCaptor =
ArgumentCaptor.forClass(ContentObserver::class.java)
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
progressProvider = ScaleAwareTransitionProgressProvider(
sourceProvider,
contentResolver
)
verify(sourceProvider).addCallback(sourceProviderListenerCaptor.capture())
verify(contentResolver).registerContentObserver(any(), any(),
animatorDurationScaleListenerCaptor.capture())
progressProvider.addCallback(sinkProvider)
}
@Test
fun onTransitionStarted_animationsEnabled_eventReceived() {
setAnimationsEnabled(true)
source.onTransitionStarted()
verify(sinkProvider).onTransitionStarted()
}
@Test
fun onTransitionStarted_animationsNotEnabled_eventNotReceived() {
setAnimationsEnabled(false)
source.onTransitionStarted()
verifyNoMoreInteractions(sinkProvider)
}
@Test
fun onTransitionEnd_animationsEnabled_eventReceived() {
setAnimationsEnabled(true)
source.onTransitionFinished()
verify(sinkProvider).onTransitionFinished()
}
@Test
fun onTransitionEnd_animationsNotEnabled_eventNotReceived() {
setAnimationsEnabled(false)
source.onTransitionFinished()
verifyNoMoreInteractions(sinkProvider)
}
@Test
fun onTransitionProgress_animationsEnabled_eventReceived() {
setAnimationsEnabled(true)
source.onTransitionProgress(42f)
verify(sinkProvider).onTransitionProgress(42f)
}
@Test
fun onTransitionProgress_animationsNotEnabled_eventNotReceived() {
setAnimationsEnabled(false)
source.onTransitionProgress(42f)
verifyNoMoreInteractions(sinkProvider)
}
private fun setAnimationsEnabled(enabled: Boolean) {
val durationScale = if (enabled) {
1f
} else {
0f
}
ValueAnimator.setDurationScale(durationScale)
animatorDurationScaleListenerCaptor.value.dispatchChange(/* selfChange= */false)
}
private val source: TransitionProgressListener
get() = sourceProviderListenerCaptor.value
}