Merge "Start fold animation only when the large screen is visible" into tm-qpr-dev am: d96b67dacb

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/22168635

Change-Id: I8b3ec638dabea6edd835c698ef2693b831276fdc
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Nicolò Mazzucato
2023-03-22 15:21:37 +00:00
committed by Automerger Merge Worker
3 changed files with 97 additions and 27 deletions

View File

@@ -16,6 +16,9 @@
package com.android.systemui.unfold.updates
import android.content.Context
import android.content.res.Configuration
import android.content.res.Resources
import android.os.Handler
import android.testing.AndroidTestingRunner
import androidx.core.util.Consumer
@@ -33,6 +36,7 @@ import com.android.systemui.unfold.updates.screen.ScreenStatusProvider.ScreenLis
import com.android.systemui.unfold.util.UnfoldKeyguardVisibilityProvider
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.capture
import com.android.systemui.util.mockito.mock
import com.google.common.truth.Truth.assertThat
import java.util.concurrent.Executor
import org.junit.Before
@@ -49,20 +53,19 @@ import org.mockito.MockitoAnnotations
@SmallTest
class DeviceFoldStateProviderTest : SysuiTestCase() {
@Mock
private lateinit var activityTypeProvider: ActivityManagerActivityTypeProvider
@Mock private lateinit var activityTypeProvider: ActivityManagerActivityTypeProvider
@Mock
private lateinit var handler: Handler
@Mock private lateinit var handler: Handler
@Mock
private lateinit var rotationChangeProvider: RotationChangeProvider
@Mock private lateinit var rotationChangeProvider: RotationChangeProvider
@Mock
private lateinit var unfoldKeyguardVisibilityProvider: UnfoldKeyguardVisibilityProvider
@Mock private lateinit var unfoldKeyguardVisibilityProvider: UnfoldKeyguardVisibilityProvider
@Captor
private lateinit var rotationListener: ArgumentCaptor<RotationListener>
@Mock private lateinit var resources: Resources
@Mock private lateinit var context: Context
@Captor private lateinit var rotationListener: ArgumentCaptor<RotationListener>
private val foldProvider = TestFoldProvider()
private val screenOnStatusProvider = TestScreenOnStatusProvider()
@@ -81,10 +84,13 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
fun setUp() {
MockitoAnnotations.initMocks(this)
val config = object : UnfoldTransitionConfig by ResourceUnfoldTransitionConfig() {
override val halfFoldedTimeoutMillis: Int
get() = HALF_OPENED_TIMEOUT_MILLIS.toInt()
}
val config =
object : UnfoldTransitionConfig by ResourceUnfoldTransitionConfig() {
override val halfFoldedTimeoutMillis: Int
get() = HALF_OPENED_TIMEOUT_MILLIS.toInt()
}
whenever(context.resources).thenReturn(resources)
whenever(context.mainExecutor).thenReturn(mContext.mainExecutor)
foldStateProvider =
DeviceFoldStateProvider(
@@ -95,6 +101,7 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
activityTypeProvider,
unfoldKeyguardVisibilityProvider,
rotationChangeProvider,
context,
context.mainExecutor,
handler
)
@@ -112,7 +119,8 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
override fun onUnfoldedScreenAvailable() {
unfoldedScreenAvailabilityUpdates.add(Unit)
}
})
}
)
foldStateProvider.start()
verify(rotationChangeProvider).addCallback(capture(rotationListener))
@@ -134,6 +142,7 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
// By default, we're on launcher.
setupForegroundActivityType(isHomeActivity = true)
setIsLargeScreen(true)
}
@Test
@@ -181,7 +190,7 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
sendHingeAngleEvent(10)
assertThat(foldUpdates)
.containsExactly(FOLD_UPDATE_START_OPENING, FOLD_UPDATE_START_CLOSING)
.containsExactly(FOLD_UPDATE_START_OPENING, FOLD_UPDATE_START_CLOSING)
assertThat(unfoldedScreenAvailabilityUpdates).hasSize(1)
}
@@ -386,8 +395,10 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
setInitialHingeAngle(START_CLOSING_ON_APPS_THRESHOLD_DEGREES)
sendHingeAngleEvent(
START_CLOSING_ON_APPS_THRESHOLD_DEGREES -
HINGE_ANGLE_CHANGE_THRESHOLD_DEGREES.toInt() - 1)
START_CLOSING_ON_APPS_THRESHOLD_DEGREES -
HINGE_ANGLE_CHANGE_THRESHOLD_DEGREES.toInt() -
1
)
assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_CLOSING)
}
@@ -429,8 +440,10 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
setInitialHingeAngle(START_CLOSING_ON_APPS_THRESHOLD_DEGREES)
sendHingeAngleEvent(
START_CLOSING_ON_APPS_THRESHOLD_DEGREES -
HINGE_ANGLE_CHANGE_THRESHOLD_DEGREES.toInt() - 1)
START_CLOSING_ON_APPS_THRESHOLD_DEGREES -
HINGE_ANGLE_CHANGE_THRESHOLD_DEGREES.toInt() -
1
)
assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_CLOSING)
}
@@ -470,7 +483,7 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
sendHingeAngleEvent(130)
sendHingeAngleEvent(120)
assertThat(foldUpdates)
.containsExactly(FOLD_UPDATE_START_OPENING, FOLD_UPDATE_START_CLOSING)
.containsExactly(FOLD_UPDATE_START_OPENING, FOLD_UPDATE_START_CLOSING)
}
@Test
@@ -531,8 +544,8 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
rotationListener.value.onRotationChanged(1)
assertThat(foldUpdates).containsExactly(
FOLD_UPDATE_START_OPENING, FOLD_UPDATE_FINISH_HALF_OPEN)
assertThat(foldUpdates)
.containsExactly(FOLD_UPDATE_START_OPENING, FOLD_UPDATE_FINISH_HALF_OPEN)
}
@Test
@@ -545,6 +558,45 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
assertThat(foldUpdates).containsExactly(FOLD_UPDATE_FINISH_CLOSED)
}
@Test
fun onFolding_onSmallScreen_tansitionDoesNotStart() {
setIsLargeScreen(false)
setInitialHingeAngle(120)
sendHingeAngleEvent(110)
sendHingeAngleEvent(100)
assertThat(foldUpdates).isEmpty()
}
@Test
fun onFolding_onLargeScreen_tansitionStarts() {
setIsLargeScreen(true)
setInitialHingeAngle(120)
sendHingeAngleEvent(110)
sendHingeAngleEvent(100)
assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_CLOSING)
}
@Test
fun onUnfold_onSmallScreen_emitsStartOpening() {
// the new display state might arrive later, so it shouldn't be used to decide to send the
// start opening event, but only for the closing.
setFoldState(folded = true)
setIsLargeScreen(false)
foldUpdates.clear()
setFoldState(folded = false)
screenOnStatusProvider.notifyScreenTurningOn()
sendHingeAngleEvent(10)
sendHingeAngleEvent(20)
screenOnStatusProvider.notifyScreenTurnedOn()
assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_OPENING)
}
private fun setupForegroundActivityType(isHomeActivity: Boolean?) {
whenever(activityTypeProvider.isHomeActivity).thenReturn(isHomeActivity)
}
@@ -566,6 +618,13 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
foldProvider.notifyFolded(folded)
}
private fun setIsLargeScreen(isLargeScreen: Boolean) {
val smallestScreenWidth = if (isLargeScreen) { 601 } else { 10 }
val configuration = Configuration()
configuration.smallestScreenWidthDp = smallestScreenWidth
whenever(resources.configuration).thenReturn(configuration)
}
private fun fireScreenOnEvent() {
screenOnStatusProvider.notifyScreenTurnedOn()
}

View File

@@ -53,4 +53,4 @@ class ScreenSizeFoldProvider(private val context: Context) : FoldProvider {
}
}
private const val INNER_SCREEN_SMALLEST_SCREEN_WIDTH_THRESHOLD_DP = 600
internal const val INNER_SCREEN_SMALLEST_SCREEN_WIDTH_THRESHOLD_DP = 600

View File

@@ -15,12 +15,14 @@
*/
package com.android.systemui.unfold.updates
import android.content.Context
import android.os.Handler
import android.os.Trace
import android.util.Log
import androidx.annotation.FloatRange
import androidx.annotation.VisibleForTesting
import androidx.core.util.Consumer
import com.android.systemui.unfold.compat.INNER_SCREEN_SMALLEST_SCREEN_WIDTH_THRESHOLD_DP
import com.android.systemui.unfold.config.UnfoldTransitionConfig
import com.android.systemui.unfold.dagger.UnfoldMain
import com.android.systemui.unfold.updates.FoldStateProvider.FoldUpdate
@@ -45,6 +47,7 @@ constructor(
private val activityTypeProvider: CurrentActivityTypeProvider,
private val unfoldKeyguardVisibilityProvider: UnfoldKeyguardVisibilityProvider,
private val rotationChangeProvider: RotationChangeProvider,
private val context: Context,
@UnfoldMain private val mainExecutor: Executor,
@UnfoldMain private val handler: Handler
) : FoldStateProvider {
@@ -119,7 +122,7 @@ constructor(
"lastHingeAngle: $lastHingeAngle, " +
"lastHingeAngleBeforeTransition: $lastHingeAngleBeforeTransition"
)
Trace.setCounter( "hinge_angle", angle.toLong())
Trace.setCounter("hinge_angle", angle.toLong())
}
val currentDirection =
@@ -136,6 +139,7 @@ constructor(
val isFullyOpened = FULLY_OPEN_DEGREES - angle < FULLY_OPEN_THRESHOLD_DEGREES
val eventNotAlreadyDispatched = lastFoldUpdate != transitionUpdate
val screenAvailableEventSent = isUnfoldHandled
val isOnLargeScreen = isOnLargeScreen()
if (
angleChangeSurpassedThreshold && // Do not react immediately to small changes in angle
@@ -144,7 +148,9 @@ constructor(
// angle range as closing threshold could overlap this range
screenAvailableEventSent && // do not send transition event if we are still in the
// process of turning on the inner display
isClosingThresholdMet(angle) // hinge angle is below certain threshold.
isClosingThresholdMet(angle) && // hinge angle is below certain threshold.
isOnLargeScreen // Avoids sending closing event when on small screen.
// Start event is sent regardless due to hall sensor.
) {
notifyFoldUpdate(transitionUpdate, lastHingeAngle)
}
@@ -233,7 +239,7 @@ constructor(
}
private fun cancelAnimation(): Unit =
notifyFoldUpdate(FOLD_UPDATE_FINISH_HALF_OPEN, lastHingeAngle)
notifyFoldUpdate(FOLD_UPDATE_FINISH_HALF_OPEN, lastHingeAngle)
private inner class ScreenStatusListener : ScreenStatusProvider.ScreenListener {
@@ -261,6 +267,11 @@ constructor(
}
}
private fun isOnLargeScreen(): Boolean {
return context.resources.configuration.smallestScreenWidthDp >
INNER_SCREEN_SMALLEST_SCREEN_WIDTH_THRESHOLD_DP
}
/** While the screen is off or the device is folded, hinge angle updates are not needed. */
private fun updateHingeAngleProviderState() {
if (isScreenOn && !isFolded) {