Merge "Start fold animation only when the large screen is visible" into tm-qpr-dev am: d96b67dacb am: 542b75a2fe
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/22168635 Change-Id: If839a995b97891ca239c4a7224af7885be3841f2 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user