summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolo' Mazzucato <nicomazz@google.com>2022-03-24 11:31:52 +0000
committerNicolo' Mazzucato <nicomazz@google.com>2022-03-24 14:53:27 +0000
commitef3dfe2a8f04905eb52c8b03928c8fd0761a69da (patch)
tree61761083df2facd3a335a804cc5b83015ccf9ef6
parent0a6a138074235175876c361efd535d3101356166 (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
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldSharedComponent.kt2
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt3
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt39
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt37
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) {