Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5906babb authored by Nicolò Mazzucato's avatar Nicolò Mazzucato Committed by Automerger Merge Worker
Browse files

Merge "Tune fold animation on top of apps" into tm-dev am: c1f95fd3

parents 5d86671a c1f95fd3
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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,
+3 −0
Original line number Diff line number Diff line
@@ -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,
+37 −2
Original line number Diff line number Diff line
@@ -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
+36 −1
Original line number Diff line number Diff line
@@ -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) {