diff options
| author | 2022-10-13 23:06:44 +0000 | |
|---|---|---|
| committer | 2022-10-13 23:06:44 +0000 | |
| commit | aea723c85482bfa2a234dddcdb2260df702f2a31 (patch) | |
| tree | b44812a45b25ff33d144b77d3cf9ea59bbed6b24 | |
| parent | a6729cea41c8dc240361cc6e159c7a9995417acf (diff) | |
| parent | 0def5f9805ca7f35a678f2437e1add37350b1bb1 (diff) | |
Merge changes from topic "cancel_unfold_anim_on_rotation" into tm-qpr-dev
* changes:
Cancel unfold animation when rotation changes
Create RotationChangeProvider in sysui
12 files changed, 288 insertions, 92 deletions
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimator.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimator.kt index d7a0b473ead6..3efdc5acb00c 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimator.kt +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimator.kt @@ -17,6 +17,7 @@ package com.android.systemui.shared.animation import android.graphics.Point import android.view.Surface +import android.view.Surface.Rotation import android.view.View import android.view.WindowManager import com.android.systemui.unfold.UnfoldTransitionProgressProvider @@ -58,14 +59,14 @@ class UnfoldMoveFromCenterAnimator @JvmOverloads constructor( * Updates display properties in order to calculate the initial position for the views * Must be called before [registerViewForAnimation] */ - fun updateDisplayProperties() { + @JvmOverloads + fun updateDisplayProperties(@Rotation rotation: Int = windowManager.defaultDisplay.rotation) { windowManager.defaultDisplay.getSize(screenSize) // Simple implementation to get current fold orientation, // this might not be correct on all devices // TODO: use JetPack WindowManager library to get the fold orientation - isVerticalFold = windowManager.defaultDisplay.rotation == Surface.ROTATION_0 || - windowManager.defaultDisplay.rotation == Surface.ROTATION_180 + isVerticalFold = rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180 } /** diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/util/NaturalRotationUnfoldProgressProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/util/NaturalRotationUnfoldProgressProvider.kt index ec938b219933..aca9907fec1b 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/unfold/util/NaturalRotationUnfoldProgressProvider.kt +++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/util/NaturalRotationUnfoldProgressProvider.kt @@ -15,12 +15,11 @@ package com.android.systemui.unfold.util import android.content.Context -import android.os.RemoteException -import android.view.IRotationWatcher -import android.view.IWindowManager import android.view.Surface import com.android.systemui.unfold.UnfoldTransitionProgressProvider import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener +import com.android.systemui.unfold.updates.RotationChangeProvider +import com.android.systemui.unfold.updates.RotationChangeProvider.RotationListener /** * [UnfoldTransitionProgressProvider] that emits transition progress only when the display has @@ -29,27 +28,21 @@ import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionPr */ class NaturalRotationUnfoldProgressProvider( private val context: Context, - private val windowManagerInterface: IWindowManager, + private val rotationChangeProvider: RotationChangeProvider, unfoldTransitionProgressProvider: UnfoldTransitionProgressProvider ) : UnfoldTransitionProgressProvider { private val scopedUnfoldTransitionProgressProvider = ScopedUnfoldTransitionProgressProvider(unfoldTransitionProgressProvider) - private val rotationWatcher = RotationWatcher() private var isNaturalRotation: Boolean = false fun init() { - try { - windowManagerInterface.watchRotation(rotationWatcher, context.display.displayId) - } catch (e: RemoteException) { - throw e.rethrowFromSystemServer() - } - - onRotationChanged(context.display.rotation) + rotationChangeProvider.addCallback(rotationListener) + rotationListener.onRotationChanged(context.display.rotation) } - private fun onRotationChanged(rotation: Int) { + private val rotationListener = RotationListener { rotation -> val isNewRotationNatural = rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180 @@ -60,12 +53,7 @@ class NaturalRotationUnfoldProgressProvider( } override fun destroy() { - try { - windowManagerInterface.removeRotationWatcher(rotationWatcher) - } catch (e: RemoteException) { - e.rethrowFromSystemServer() - } - + rotationChangeProvider.removeCallback(rotationListener) scopedUnfoldTransitionProgressProvider.destroy() } @@ -76,10 +64,4 @@ class NaturalRotationUnfoldProgressProvider( override fun removeCallback(listener: TransitionProgressListener) { scopedUnfoldTransitionProgressProvider.removeCallback(listener) } - - private inner class RotationWatcher : IRotationWatcher.Stub() { - override fun onRotationChanged(rotation: Int) { - this@NaturalRotationUnfoldProgressProvider.onRotationChanged(rotation) - } - } } diff --git a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt index fc20ac241e38..6ed3a093c8e3 100644 --- a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt +++ b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt @@ -26,8 +26,6 @@ import android.os.Trace import android.view.Choreographer import android.view.Display import android.view.DisplayInfo -import android.view.IRotationWatcher -import android.view.IWindowManager import android.view.Surface import android.view.SurfaceControl import android.view.SurfaceControlViewHost @@ -40,6 +38,7 @@ import com.android.systemui.statusbar.LightRevealEffect 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.util.traceSection import com.android.wm.shell.displayareahelper.DisplayAreaHelper import java.util.Optional @@ -58,7 +57,7 @@ constructor( private val displayAreaHelper: Optional<DisplayAreaHelper>, @Main private val executor: Executor, @UiBackground private val backgroundExecutor: Executor, - private val windowManagerInterface: IWindowManager + private val rotationChangeProvider: RotationChangeProvider, ) { private val transitionListener = TransitionListener() @@ -78,7 +77,7 @@ constructor( fun init() { deviceStateManager.registerCallback(executor, FoldListener()) unfoldTransitionProgressProvider.addCallback(transitionListener) - windowManagerInterface.watchRotation(rotationWatcher, context.display.displayId) + rotationChangeProvider.addCallback(rotationWatcher) val containerBuilder = SurfaceControl.Builder(SurfaceSession()) @@ -86,7 +85,9 @@ constructor( .setName("unfold-overlay-container") displayAreaHelper.get().attachToRootDisplayArea( - Display.DEFAULT_DISPLAY, containerBuilder) { builder -> + Display.DEFAULT_DISPLAY, + containerBuilder + ) { builder -> executor.execute { overlayContainer = builder.build() @@ -244,8 +245,8 @@ constructor( } } - private inner class RotationWatcher : IRotationWatcher.Stub() { - override fun onRotationChanged(newRotation: Int) = + private inner class RotationWatcher : RotationChangeProvider.RotationListener { + override fun onRotationChanged(newRotation: Int) { traceSection("UnfoldLightRevealOverlayAnimation#onRotationChanged") { if (currentRotation != newRotation) { currentRotation = newRotation @@ -253,6 +254,7 @@ constructor( root?.relayout(getLayoutParams()) } } + } } private inner class FoldListener : diff --git a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt index eea6ac0e72e9..59ad24a3e7bb 100644 --- a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt +++ b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt @@ -17,11 +17,11 @@ package com.android.systemui.unfold import android.content.Context -import android.view.IWindowManager import com.android.systemui.keyguard.LifecycleScreenStatusProvider import com.android.systemui.unfold.config.UnfoldTransitionConfig import com.android.systemui.unfold.system.SystemUnfoldSharedModule import com.android.systemui.unfold.updates.FoldStateProvider +import com.android.systemui.unfold.updates.RotationChangeProvider import com.android.systemui.unfold.updates.screen.ScreenStatusProvider import com.android.systemui.unfold.util.NaturalRotationUnfoldProgressProvider import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider @@ -65,11 +65,11 @@ class UnfoldTransitionModule { @Singleton fun provideNaturalRotationProgressProvider( context: Context, - windowManager: IWindowManager, + rotationChangeProvider: RotationChangeProvider, unfoldTransitionProgressProvider: Optional<UnfoldTransitionProgressProvider> ): Optional<NaturalRotationUnfoldProgressProvider> = unfoldTransitionProgressProvider.map { provider -> - NaturalRotationUnfoldProgressProvider(context, windowManager, provider) + NaturalRotationUnfoldProgressProvider(context, rotationChangeProvider, provider) } @Provides diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt index 7e0704007700..e18dd3a3c846 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt @@ -25,16 +25,21 @@ import com.android.systemui.unfold.config.ResourceUnfoldTransitionConfig import com.android.systemui.unfold.config.UnfoldTransitionConfig import com.android.systemui.unfold.system.ActivityManagerActivityTypeProvider import com.android.systemui.unfold.updates.FoldProvider.FoldCallback +import com.android.systemui.unfold.updates.RotationChangeProvider.RotationListener import com.android.systemui.unfold.updates.hinge.HingeAngleProvider import com.android.systemui.unfold.updates.screen.ScreenStatusProvider import com.android.systemui.unfold.updates.screen.ScreenStatusProvider.ScreenListener import com.android.systemui.util.mockito.any +import com.android.systemui.util.mockito.capture import com.google.common.truth.Truth.assertThat import java.util.concurrent.Executor import org.junit.Before import org.junit.Test import org.junit.runner.RunWith +import org.mockito.ArgumentCaptor +import org.mockito.Captor import org.mockito.Mock +import org.mockito.Mockito.verify import org.mockito.Mockito.`when` as whenever import org.mockito.MockitoAnnotations @@ -48,6 +53,12 @@ class DeviceFoldStateProviderTest : SysuiTestCase() { @Mock private lateinit var handler: Handler + @Mock + private lateinit var rotationChangeProvider: RotationChangeProvider + + @Captor + private lateinit var rotationListener: ArgumentCaptor<RotationListener> + private val foldProvider = TestFoldProvider() private val screenOnStatusProvider = TestScreenOnStatusProvider() private val testHingeAngleProvider = TestHingeAngleProvider() @@ -76,6 +87,7 @@ class DeviceFoldStateProviderTest : SysuiTestCase() { screenOnStatusProvider, foldProvider, activityTypeProvider, + rotationChangeProvider, context.mainExecutor, handler ) @@ -92,6 +104,8 @@ class DeviceFoldStateProviderTest : SysuiTestCase() { }) foldStateProvider.start() + verify(rotationChangeProvider).addCallback(capture(rotationListener)) + whenever(handler.postDelayed(any<Runnable>(), any())).then { invocationOnMock -> scheduledRunnable = invocationOnMock.getArgument<Runnable>(0) scheduledRunnableDelay = invocationOnMock.getArgument<Long>(1) @@ -372,6 +386,27 @@ class DeviceFoldStateProviderTest : SysuiTestCase() { assertThat(testHingeAngleProvider.isStarted).isFalse() } + @Test + fun onRotationChanged_whileInProgress_cancelled() { + setFoldState(folded = false) + assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_OPENING) + + rotationListener.value.onRotationChanged(1) + + assertThat(foldUpdates).containsExactly( + FOLD_UPDATE_START_OPENING, FOLD_UPDATE_FINISH_HALF_OPEN) + } + + @Test + fun onRotationChanged_whileNotInProgress_noUpdates() { + setFoldState(folded = true) + assertThat(foldUpdates).containsExactly(FOLD_UPDATE_FINISH_CLOSED) + + rotationListener.value.onRotationChanged(1) + + assertThat(foldUpdates).containsExactly(FOLD_UPDATE_FINISH_CLOSED) + } + private fun setupForegroundActivityType(isHomeActivity: Boolean?) { whenever(activityTypeProvider.isHomeActivity).thenReturn(isHomeActivity) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/RotationChangeProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/RotationChangeProviderTest.kt new file mode 100644 index 000000000000..85cfef727954 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/RotationChangeProviderTest.kt @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2022 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.updates + +import android.testing.AndroidTestingRunner +import android.view.IRotationWatcher +import android.view.IWindowManager +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.unfold.updates.RotationChangeProvider.RotationListener +import com.android.systemui.util.concurrency.FakeExecutor +import com.android.systemui.util.time.FakeSystemClock +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentCaptor +import org.mockito.ArgumentMatchers.any +import org.mockito.ArgumentMatchers.anyInt +import org.mockito.Captor +import org.mockito.Mock +import org.mockito.Mockito.verify +import org.mockito.Mockito.verifyNoMoreInteractions +import org.mockito.MockitoAnnotations + +@RunWith(AndroidTestingRunner::class) +@SmallTest +class RotationChangeProviderTest : SysuiTestCase() { + + private lateinit var rotationChangeProvider: RotationChangeProvider + + @Mock lateinit var windowManagerInterface: IWindowManager + @Mock lateinit var listener: RotationListener + @Captor lateinit var rotationWatcher: ArgumentCaptor<IRotationWatcher> + private val fakeExecutor = FakeExecutor(FakeSystemClock()) + + @Before + fun setup() { + MockitoAnnotations.initMocks(this) + rotationChangeProvider = + RotationChangeProvider(windowManagerInterface, context, fakeExecutor) + rotationChangeProvider.addCallback(listener) + fakeExecutor.runAllReady() + verify(windowManagerInterface).watchRotation(rotationWatcher.capture(), anyInt()) + } + + @Test + fun onRotationChanged_rotationUpdated_listenerReceivesIt() { + sendRotationUpdate(42) + + verify(listener).onRotationChanged(42) + } + + @Test + fun onRotationChanged_subscribersRemoved_noRotationChangeReceived() { + sendRotationUpdate(42) + verify(listener).onRotationChanged(42) + + rotationChangeProvider.removeCallback(listener) + fakeExecutor.runAllReady() + sendRotationUpdate(43) + + verify(windowManagerInterface).removeRotationWatcher(any()) + verifyNoMoreInteractions(listener) + } + + private fun sendRotationUpdate(newRotation: Int) { + rotationWatcher.value.onRotationChanged(newRotation) + fakeExecutor.runAllReady() + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/util/NaturalRotationUnfoldProgressProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/util/NaturalRotationUnfoldProgressProviderTest.kt index b2cedbf8d606..a25469bfc09b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/unfold/util/NaturalRotationUnfoldProgressProviderTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/util/NaturalRotationUnfoldProgressProviderTest.kt @@ -16,18 +16,19 @@ package com.android.systemui.unfold.util import android.testing.AndroidTestingRunner -import android.view.IRotationWatcher -import android.view.IWindowManager import android.view.Surface import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.unfold.TestUnfoldTransitionProvider import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener -import com.android.systemui.util.mockito.any +import com.android.systemui.unfold.updates.RotationChangeProvider +import com.android.systemui.unfold.updates.RotationChangeProvider.RotationListener +import com.android.systemui.util.mockito.capture import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentCaptor +import org.mockito.Captor import org.mockito.Mock import org.mockito.Mockito.clearInvocations import org.mockito.Mockito.never @@ -38,32 +39,26 @@ import org.mockito.MockitoAnnotations @SmallTest class NaturalRotationUnfoldProgressProviderTest : SysuiTestCase() { - @Mock - lateinit var windowManager: IWindowManager + @Mock lateinit var rotationChangeProvider: RotationChangeProvider private val sourceProvider = TestUnfoldTransitionProvider() - @Mock - lateinit var transitionListener: TransitionProgressListener + @Mock lateinit var transitionListener: TransitionProgressListener - lateinit var progressProvider: NaturalRotationUnfoldProgressProvider + @Captor private lateinit var rotationListenerCaptor: ArgumentCaptor<RotationListener> - private val rotationWatcherCaptor = - ArgumentCaptor.forClass(IRotationWatcher.Stub::class.java) + lateinit var progressProvider: NaturalRotationUnfoldProgressProvider @Before fun setUp() { MockitoAnnotations.initMocks(this) - progressProvider = NaturalRotationUnfoldProgressProvider( - context, - windowManager, - sourceProvider - ) + progressProvider = + NaturalRotationUnfoldProgressProvider(context, rotationChangeProvider, sourceProvider) progressProvider.init() - verify(windowManager).watchRotation(rotationWatcherCaptor.capture(), any()) + verify(rotationChangeProvider).addCallback(capture(rotationListenerCaptor)) progressProvider.addCallback(transitionListener) } @@ -127,6 +122,6 @@ class NaturalRotationUnfoldProgressProviderTest : SysuiTestCase() { } private fun onRotationChanged(rotation: Int) { - rotationWatcherCaptor.value.onRotationChanged(rotation) + rotationListenerCaptor.value.onRotationChanged(rotation) } } diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedComponent.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedComponent.kt index a5ec0a454412..5a868a4df354 100644 --- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedComponent.kt +++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedComponent.kt @@ -20,10 +20,12 @@ import android.content.ContentResolver import android.content.Context import android.hardware.SensorManager import android.os.Handler +import android.view.IWindowManager import com.android.systemui.unfold.config.UnfoldTransitionConfig import com.android.systemui.unfold.dagger.UnfoldBackground import com.android.systemui.unfold.dagger.UnfoldMain import com.android.systemui.unfold.updates.FoldProvider +import com.android.systemui.unfold.updates.RotationChangeProvider import com.android.systemui.unfold.updates.screen.ScreenStatusProvider import com.android.systemui.unfold.util.CurrentActivityTypeProvider import com.android.systemui.unfold.util.UnfoldTransitionATracePrefix @@ -39,11 +41,11 @@ import javax.inject.Singleton * * This component is meant to be used for places that don't use dagger. By providing those * parameters to the factory, all dagger objects are correctly instantiated. See - * [createUnfoldTransitionProgressProvider] for an example. + * [createUnfoldSharedComponent] for an example. */ @Singleton @Component(modules = [UnfoldSharedModule::class]) -internal interface UnfoldSharedComponent { +interface UnfoldSharedComponent { @Component.Factory interface Factory { @@ -58,9 +60,11 @@ internal interface UnfoldSharedComponent { @BindsInstance @UnfoldMain executor: Executor, @BindsInstance @UnfoldBackground backgroundExecutor: Executor, @BindsInstance @UnfoldTransitionATracePrefix tracingTagPrefix: String, + @BindsInstance windowManager: IWindowManager, @BindsInstance contentResolver: ContentResolver = context.contentResolver ): UnfoldSharedComponent } val unfoldTransitionProvider: Optional<UnfoldTransitionProgressProvider> + val rotationChangeProvider: RotationChangeProvider } diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt index 402dd8474bc4..a1ed17844e8e 100644 --- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt +++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt @@ -20,6 +20,7 @@ package com.android.systemui.unfold import android.content.Context import android.hardware.SensorManager import android.os.Handler +import android.view.IWindowManager import com.android.systemui.unfold.config.UnfoldTransitionConfig import com.android.systemui.unfold.updates.FoldProvider import com.android.systemui.unfold.updates.screen.ScreenStatusProvider @@ -27,14 +28,15 @@ import com.android.systemui.unfold.util.CurrentActivityTypeProvider import java.util.concurrent.Executor /** - * Factory for [UnfoldTransitionProgressProvider]. + * Factory for [UnfoldSharedComponent]. * - * This is needed as Launcher has to create the object manually. If dagger is available, this object - * is provided in [UnfoldSharedModule]. + * This wraps the autogenerated factory (for discoverability), and is needed as Launcher has to + * create the object manually. If dagger is available, this object is provided in + * [UnfoldSharedModule]. * * This should **never** be called from sysui, as the object is already provided in that process. */ -fun createUnfoldTransitionProgressProvider( +fun createUnfoldSharedComponent( context: Context, config: UnfoldTransitionConfig, screenStatusProvider: ScreenStatusProvider, @@ -44,8 +46,9 @@ fun createUnfoldTransitionProgressProvider( mainHandler: Handler, mainExecutor: Executor, backgroundExecutor: Executor, - tracingTagPrefix: String -): UnfoldTransitionProgressProvider = + tracingTagPrefix: String, + windowManager: IWindowManager, +): UnfoldSharedComponent = DaggerUnfoldSharedComponent.factory() .create( context, @@ -57,9 +60,6 @@ fun createUnfoldTransitionProgressProvider( mainHandler, mainExecutor, backgroundExecutor, - tracingTagPrefix) - .unfoldTransitionProvider - .orElse(null) - ?: throw IllegalStateException( - "Trying to create " + - "UnfoldTransitionProgressProvider when the transition is disabled") + tracingTagPrefix, + windowManager, + ) diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionProgressProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionProgressProvider.kt index d54481c72bfd..7117aafba54a 100644 --- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionProgressProvider.kt +++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionProgressProvider.kt @@ -26,7 +26,8 @@ import com.android.systemui.unfold.util.CallbackController * * onTransitionProgress callback could be called on each frame. * - * Use [createUnfoldTransitionProgressProvider] to create instances of this interface + * Use [createUnfoldSharedComponent] to create instances of this interface when dagger is not + * available. */ interface UnfoldTransitionProgressProvider : CallbackController<TransitionProgressListener> { diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt index 19cfc805d17b..07473b30dd58 100644 --- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt +++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt @@ -24,6 +24,7 @@ import com.android.systemui.unfold.config.UnfoldTransitionConfig import com.android.systemui.unfold.dagger.UnfoldMain import com.android.systemui.unfold.updates.FoldStateProvider.FoldUpdate import com.android.systemui.unfold.updates.FoldStateProvider.FoldUpdatesListener +import com.android.systemui.unfold.updates.RotationChangeProvider.RotationListener import com.android.systemui.unfold.updates.hinge.FULLY_CLOSED_DEGREES import com.android.systemui.unfold.updates.hinge.FULLY_OPEN_DEGREES import com.android.systemui.unfold.updates.hinge.HingeAngleProvider @@ -40,22 +41,24 @@ constructor( private val screenStatusProvider: ScreenStatusProvider, private val foldProvider: FoldProvider, private val activityTypeProvider: CurrentActivityTypeProvider, + private val rotationChangeProvider: RotationChangeProvider, @UnfoldMain private val mainExecutor: Executor, @UnfoldMain private val handler: Handler ) : FoldStateProvider { private val outputListeners: MutableList<FoldUpdatesListener> = mutableListOf() - @FoldUpdate - private var lastFoldUpdate: Int? = null + @FoldUpdate private var lastFoldUpdate: Int? = null - @FloatRange(from = 0.0, to = 180.0) - private var lastHingeAngle: Float = 0f + @FloatRange(from = 0.0, to = 180.0) private var lastHingeAngle: Float = 0f private val hingeAngleListener = HingeAngleListener() private val screenListener = ScreenStatusListener() private val foldStateListener = FoldStateListener() - private val timeoutRunnable = TimeoutRunnable() + private val timeoutRunnable = Runnable { cancelAnimation() } + private val rotationListener = RotationListener { + if (isTransitionInProgress) cancelAnimation() + } /** * Time after which [FOLD_UPDATE_FINISH_HALF_OPEN] is emitted following a @@ -72,6 +75,7 @@ constructor( foldProvider.registerCallback(foldStateListener, mainExecutor) screenStatusProvider.addCallback(screenListener) hingeAngleProvider.addCallback(hingeAngleListener) + rotationChangeProvider.addCallback(rotationListener) } override fun stop() { @@ -79,6 +83,7 @@ constructor( foldProvider.unregisterCallback(foldStateListener) hingeAngleProvider.removeCallback(hingeAngleListener) hingeAngleProvider.stop() + rotationChangeProvider.removeCallback(rotationListener) } override fun addCallback(listener: FoldUpdatesListener) { @@ -90,14 +95,15 @@ constructor( } override val isFinishedOpening: Boolean - get() = !isFolded && + get() = + !isFolded && (lastFoldUpdate == FOLD_UPDATE_FINISH_FULL_OPEN || - lastFoldUpdate == FOLD_UPDATE_FINISH_HALF_OPEN) + lastFoldUpdate == FOLD_UPDATE_FINISH_HALF_OPEN) private val isTransitionInProgress: Boolean get() = lastFoldUpdate == FOLD_UPDATE_START_OPENING || - lastFoldUpdate == FOLD_UPDATE_START_CLOSING + lastFoldUpdate == FOLD_UPDATE_START_CLOSING private fun onHingeAngle(angle: Float) { if (DEBUG) { @@ -168,7 +174,7 @@ constructor( private fun notifyFoldUpdate(@FoldUpdate update: Int) { if (DEBUG) { - Log.d(TAG, stateToString(update)) + Log.d(TAG, update.name()) } outputListeners.forEach { it.onFoldUpdate(update) } lastFoldUpdate = update @@ -185,6 +191,8 @@ constructor( handler.removeCallbacks(timeoutRunnable) } + private fun cancelAnimation(): Unit = notifyFoldUpdate(FOLD_UPDATE_FINISH_HALF_OPEN) + private inner class ScreenStatusListener : ScreenStatusProvider.ScreenListener { override fun onScreenTurnedOn() { @@ -225,16 +233,10 @@ constructor( onHingeAngle(angle) } } - - private inner class TimeoutRunnable : Runnable { - override fun run() { - notifyFoldUpdate(FOLD_UPDATE_FINISH_HALF_OPEN) - } - } } -private fun stateToString(@FoldUpdate update: Int): String { - return when (update) { +fun @receiver:FoldUpdate Int.name() = + when (this) { FOLD_UPDATE_START_OPENING -> "START_OPENING" FOLD_UPDATE_START_CLOSING -> "START_CLOSING" FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE -> "UNFOLDED_SCREEN_AVAILABLE" @@ -243,15 +245,12 @@ private fun stateToString(@FoldUpdate update: Int): String { FOLD_UPDATE_FINISH_CLOSED -> "FINISH_CLOSED" else -> "UNKNOWN" } -} private const val TAG = "DeviceFoldProvider" private const val DEBUG = false /** Threshold after which we consider the device fully unfolded. */ -@VisibleForTesting -const val FULLY_OPEN_THRESHOLD_DEGREES = 15f +@VisibleForTesting const val FULLY_OPEN_THRESHOLD_DEGREES = 15f /** Fold animation on top of apps only when the angle exceeds this threshold. */ -@VisibleForTesting -const val START_CLOSING_ON_APPS_THRESHOLD_DEGREES = 60 +@VisibleForTesting const val START_CLOSING_ON_APPS_THRESHOLD_DEGREES = 60 diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/RotationChangeProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/RotationChangeProvider.kt new file mode 100644 index 000000000000..0cf8224d3a3f --- /dev/null +++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/RotationChangeProvider.kt @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2022 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.updates + +import android.content.Context +import android.os.RemoteException +import android.view.IRotationWatcher +import android.view.IWindowManager +import android.view.Surface.Rotation +import com.android.systemui.unfold.dagger.UnfoldMain +import com.android.systemui.unfold.util.CallbackController +import java.util.concurrent.Executor +import javax.inject.Inject + +/** + * Allows to subscribe to rotation changes. + * + * This is needed as rotation updates from [IWindowManager] are received in a binder thread, while + * most of the times we want them in the main one. Updates are provided for the display associated + * to [context]. + */ +class RotationChangeProvider +@Inject +constructor( + private val windowManagerInterface: IWindowManager, + private val context: Context, + @UnfoldMain private val mainExecutor: Executor, +) : CallbackController<RotationChangeProvider.RotationListener> { + + private val listeners = mutableListOf<RotationListener>() + + private val rotationWatcher = RotationWatcher() + + override fun addCallback(listener: RotationListener) { + mainExecutor.execute { + if (listeners.isEmpty()) { + subscribeToRotation() + } + listeners += listener + } + } + + override fun removeCallback(listener: RotationListener) { + mainExecutor.execute { + listeners -= listener + if (listeners.isEmpty()) { + unsubscribeToRotation() + } + } + } + + private fun subscribeToRotation() { + try { + windowManagerInterface.watchRotation(rotationWatcher, context.displayId) + } catch (e: RemoteException) { + throw e.rethrowFromSystemServer() + } + } + + private fun unsubscribeToRotation() { + try { + windowManagerInterface.removeRotationWatcher(rotationWatcher) + } catch (e: RemoteException) { + throw e.rethrowFromSystemServer() + } + } + + /** Gets notified of rotation changes. */ + fun interface RotationListener { + /** Called once rotation changes. */ + fun onRotationChanged(@Rotation newRotation: Int) + } + + private inner class RotationWatcher : IRotationWatcher.Stub() { + override fun onRotationChanged(rotation: Int) { + mainExecutor.execute { listeners.forEach { it.onRotationChanged(rotation) } } + } + } +} |