diff options
| author | Nicolo' Mazzucato <nicomazz@google.com> | 2022-03-24 11:31:52 +0000 |
|---|---|---|
| committer | Nicolo' Mazzucato <nicomazz@google.com> | 2022-03-24 14:53:27 +0000 |
| commit | ef3dfe2a8f04905eb52c8b03928c8fd0761a69da (patch) | |
| tree | 61761083df2facd3a335a804cc5b83015ccf9ef6 | |
| parent | 0a6a138074235175876c361efd535d3101356166 (diff) | |
Tune fold animation on top of apps
On top of apps, the fold animation is triggered only after a threshold. On Launcher, there is not threshold.
In this way, we don't show fold animation while apps might be handling table top/half_folded state.
+ timeout to finish the animation made shorter
Test: atest DeviceFoldStateProviderTest
Bug: 225185239
Change-Id: Idaed140cec723ab54ed8c75aaf4a8e80261dc0eb
4 files changed, 78 insertions, 3 deletions
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldSharedComponent.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldSharedComponent.kt index 15593ea5f0e4..9e5aeb84b624 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldSharedComponent.kt +++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldSharedComponent.kt @@ -16,6 +16,7 @@ package com.android.systemui.unfold +import android.app.ActivityManager import android.content.ContentResolver import android.content.Context import android.hardware.SensorManager @@ -51,6 +52,7 @@ internal interface UnfoldSharedComponent { @BindsInstance config: UnfoldTransitionConfig, @BindsInstance screenStatusProvider: ScreenStatusProvider, @BindsInstance deviceStateManager: DeviceStateManager, + @BindsInstance activityManager: ActivityManager, @BindsInstance sensorManager: SensorManager, @BindsInstance @Main handler: Handler, @BindsInstance @Main executor: Executor, diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt index 8e4ff9bc9133..cc56007c431a 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt +++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt @@ -17,6 +17,7 @@ package com.android.systemui.unfold +import android.app.ActivityManager import android.content.Context import android.hardware.SensorManager import android.hardware.devicestate.DeviceStateManager @@ -39,6 +40,7 @@ fun createUnfoldTransitionProgressProvider( config: UnfoldTransitionConfig, screenStatusProvider: ScreenStatusProvider, deviceStateManager: DeviceStateManager, + activityManager: ActivityManager, sensorManager: SensorManager, mainHandler: Handler, mainExecutor: Executor, @@ -51,6 +53,7 @@ fun createUnfoldTransitionProgressProvider( config, screenStatusProvider, deviceStateManager, + activityManager, sensorManager, mainHandler, mainExecutor, diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt index 24ecf8781a18..eb1181d98bec 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt +++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt @@ -16,6 +16,8 @@ package com.android.systemui.unfold.updates import android.annotation.FloatRange +import android.app.ActivityManager +import android.app.WindowConfiguration.ACTIVITY_TYPE_HOME import android.content.Context import android.hardware.devicestate.DeviceStateManager import android.os.Handler @@ -39,6 +41,7 @@ constructor( private val hingeAngleProvider: HingeAngleProvider, private val screenStatusProvider: ScreenStatusProvider, private val deviceStateManager: DeviceStateManager, + private val activityManager: ActivityManager, @Main private val mainExecutor: Executor, @Main private val handler: Handler ) : FoldStateProvider { @@ -92,10 +95,12 @@ constructor( } val isClosing = angle < lastHingeAngle + val closingThreshold = getClosingThreshold() + val closingThresholdMet = closingThreshold == null || angle < closingThreshold val isFullyOpened = FULLY_OPEN_DEGREES - angle < FULLY_OPEN_THRESHOLD_DEGREES val closingEventDispatched = lastFoldUpdate == FOLD_UPDATE_START_CLOSING - if (isClosing && !closingEventDispatched && !isFullyOpened) { + if (isClosing && closingThresholdMet && !closingEventDispatched && !isFullyOpened) { notifyFoldUpdate(FOLD_UPDATE_START_CLOSING) } @@ -113,6 +118,33 @@ constructor( outputListeners.forEach { it.onHingeAngleUpdate(angle) } } + /** + * Fold animation should be started only after the threshold returned here. + * + * This has been introduced because the fold animation might be distracting/unwanted on top of + * apps that support table-top/HALF_FOLDED mode. Only for launcher, there is no threshold. + */ + private fun getClosingThreshold(): Int? { + val activityType = + activityManager + .getRunningTasks(/* maxNum= */ 1) + ?.getOrNull(0) + ?.configuration + ?.windowConfiguration + ?.activityType + ?: return null + + if (DEBUG) { + Log.d(TAG, "activityType=" + activityType) + } + + return if (activityType == ACTIVITY_TYPE_HOME) { + null + } else { + START_CLOSING_ON_APPS_THRESHOLD_DEGREES + } + } + private inner class FoldStateListener(context: Context) : DeviceStateManager.FoldStateListener( context, @@ -199,7 +231,10 @@ private const val DEBUG = false * Time after which [FOLD_UPDATE_FINISH_HALF_OPEN] is emitted following a * [FOLD_UPDATE_START_CLOSING] or [FOLD_UPDATE_START_OPENING] event, if an end state is not reached. */ -@VisibleForTesting const val HALF_OPENED_TIMEOUT_MILLIS = 1000L +@VisibleForTesting const val HALF_OPENED_TIMEOUT_MILLIS = 600L /** Threshold after which we consider the device fully unfolded. */ @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 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 f43dc6c5bc83..7ac243452222 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 @@ -16,6 +16,11 @@ package com.android.systemui.unfold.updates +import android.app.ActivityManager +import android.app.ActivityManager.RunningTaskInfo +import android.app.WindowConfiguration.ACTIVITY_TYPE_HOME +import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD +import android.app.WindowConfiguration.ActivityType import android.hardware.devicestate.DeviceStateManager import android.hardware.devicestate.DeviceStateManager.FoldStateListener import android.os.Handler @@ -30,7 +35,6 @@ import com.android.systemui.unfold.util.FoldableDeviceStates import com.android.systemui.unfold.util.FoldableTestUtils import com.android.systemui.util.mockito.any import com.google.common.truth.Truth.assertThat -import java.lang.Exception import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -51,6 +55,8 @@ class DeviceFoldStateProviderTest : SysuiTestCase() { @Mock private lateinit var deviceStateManager: DeviceStateManager + @Mock private lateinit var activityManager: ActivityManager + @Mock private lateinit var handler: Handler @Captor private lateinit var foldStateListenerCaptor: ArgumentCaptor<FoldStateListener> @@ -80,6 +86,7 @@ class DeviceFoldStateProviderTest : SysuiTestCase() { hingeAngleProvider, screenStatusProvider, deviceStateManager, + activityManager, context.mainExecutor, handler) @@ -113,6 +120,9 @@ class DeviceFoldStateProviderTest : SysuiTestCase() { } null } + + // By default, we're on launcher. + setupForegroundActivityType(ACTIVITY_TYPE_HOME) } @Test @@ -258,6 +268,31 @@ class DeviceFoldStateProviderTest : SysuiTestCase() { } } + @Test + fun startClosingEvent_whileNotOnLauncher_doesNotTriggerBeforeThreshold() { + setupForegroundActivityType(ACTIVITY_TYPE_STANDARD) + sendHingeAngleEvent(180) + + sendHingeAngleEvent(START_CLOSING_ON_APPS_THRESHOLD_DEGREES + 1) + + assertThat(foldUpdates).isEmpty() + } + + @Test + fun startClosingEvent_whileNotOnLauncher_triggersAfterThreshold() { + setupForegroundActivityType(ACTIVITY_TYPE_STANDARD) + sendHingeAngleEvent(START_CLOSING_ON_APPS_THRESHOLD_DEGREES) + + sendHingeAngleEvent(START_CLOSING_ON_APPS_THRESHOLD_DEGREES - 1) + + assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_CLOSING) + } + + private fun setupForegroundActivityType(@ActivityType type: Int) { + val taskInfo = RunningTaskInfo().apply { topActivityType = type } + whenever(activityManager.getRunningTasks(1)).thenReturn(listOf(taskInfo)) + } + private fun simulateTimeout(waitTime: Long = HALF_OPENED_TIMEOUT_MILLIS) { val runnableDelay = scheduledRunnableDelay ?: throw Exception("No runnable scheduled.") if (waitTime >= runnableDelay) { |
