Merge "Add a threshold to the trigger fold animation" into tm-qpr-dev
This commit is contained in:
@@ -61,8 +61,6 @@ class FoldStateLoggingProviderImpl(
|
|||||||
foldStateProvider.stop()
|
foldStateProvider.stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onHingeAngleUpdate(angle: Float) {}
|
|
||||||
|
|
||||||
override fun onFoldUpdate(@FoldUpdate update: Int) {
|
override fun onFoldUpdate(@FoldUpdate update: Int) {
|
||||||
val now = clock.elapsedRealtime()
|
val now = clock.elapsedRealtime()
|
||||||
when (update) {
|
when (update) {
|
||||||
@@ -77,6 +75,10 @@ class FoldStateLoggingProviderImpl(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onUnfoldedScreenAvailable() {
|
||||||
|
Log.d(TAG, "Unfolded screen available")
|
||||||
|
}
|
||||||
|
|
||||||
private fun dispatchState(@LoggedFoldedStates current: Int) {
|
private fun dispatchState(@LoggedFoldedStates current: Int) {
|
||||||
val now = clock.elapsedRealtime()
|
val now = clock.elapsedRealtime()
|
||||||
val previous = lastState
|
val previous = lastState
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_FULL_OPEN
|
|||||||
import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_HALF_OPEN
|
import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_HALF_OPEN
|
||||||
import com.android.systemui.unfold.updates.FOLD_UPDATE_START_CLOSING
|
import com.android.systemui.unfold.updates.FOLD_UPDATE_START_CLOSING
|
||||||
import com.android.systemui.unfold.updates.FOLD_UPDATE_START_OPENING
|
import com.android.systemui.unfold.updates.FOLD_UPDATE_START_OPENING
|
||||||
import com.android.systemui.unfold.updates.FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE
|
|
||||||
import com.android.systemui.unfold.util.TestFoldStateProvider
|
import com.android.systemui.unfold.util.TestFoldStateProvider
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
@@ -50,7 +49,7 @@ class PhysicsBasedUnfoldTransitionProgressProviderTest : SysuiTestCase() {
|
|||||||
runOnMainThreadWithInterval(
|
runOnMainThreadWithInterval(
|
||||||
{ foldStateProvider.sendFoldUpdate(FOLD_UPDATE_START_OPENING) },
|
{ foldStateProvider.sendFoldUpdate(FOLD_UPDATE_START_OPENING) },
|
||||||
{ foldStateProvider.sendHingeAngleUpdate(10f) },
|
{ foldStateProvider.sendHingeAngleUpdate(10f) },
|
||||||
{ foldStateProvider.sendFoldUpdate(FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE) },
|
{ foldStateProvider.sendUnfoldedScreenAvailable() },
|
||||||
{ foldStateProvider.sendHingeAngleUpdate(90f) },
|
{ foldStateProvider.sendHingeAngleUpdate(90f) },
|
||||||
{ foldStateProvider.sendHingeAngleUpdate(180f) },
|
{ foldStateProvider.sendHingeAngleUpdate(180f) },
|
||||||
{ foldStateProvider.sendFoldUpdate(FOLD_UPDATE_FINISH_FULL_OPEN) },
|
{ foldStateProvider.sendFoldUpdate(FOLD_UPDATE_FINISH_FULL_OPEN) },
|
||||||
@@ -67,7 +66,7 @@ class PhysicsBasedUnfoldTransitionProgressProviderTest : SysuiTestCase() {
|
|||||||
runOnMainThreadWithInterval(
|
runOnMainThreadWithInterval(
|
||||||
{ foldStateProvider.sendFoldUpdate(FOLD_UPDATE_START_OPENING) },
|
{ foldStateProvider.sendFoldUpdate(FOLD_UPDATE_START_OPENING) },
|
||||||
{ foldStateProvider.sendHingeAngleUpdate(10f) },
|
{ foldStateProvider.sendHingeAngleUpdate(10f) },
|
||||||
{ foldStateProvider.sendFoldUpdate(FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE) },
|
{ foldStateProvider.sendUnfoldedScreenAvailable() },
|
||||||
{ foldStateProvider.sendHingeAngleUpdate(90f) },
|
{ foldStateProvider.sendHingeAngleUpdate(90f) },
|
||||||
{ foldStateProvider.sendHingeAngleUpdate(180f) },
|
{ foldStateProvider.sendHingeAngleUpdate(180f) },
|
||||||
{ foldStateProvider.sendFoldUpdate(FOLD_UPDATE_FINISH_FULL_OPEN) },
|
{ foldStateProvider.sendFoldUpdate(FOLD_UPDATE_FINISH_FULL_OPEN) },
|
||||||
@@ -84,7 +83,7 @@ class PhysicsBasedUnfoldTransitionProgressProviderTest : SysuiTestCase() {
|
|||||||
{ foldStateProvider.sendHingeAngleUpdate(90f) },
|
{ foldStateProvider.sendHingeAngleUpdate(90f) },
|
||||||
{ foldStateProvider.sendHingeAngleUpdate(180f) },
|
{ foldStateProvider.sendHingeAngleUpdate(180f) },
|
||||||
{ foldStateProvider.sendFoldUpdate(FOLD_UPDATE_FINISH_FULL_OPEN) },
|
{ foldStateProvider.sendFoldUpdate(FOLD_UPDATE_FINISH_FULL_OPEN) },
|
||||||
{ foldStateProvider.sendFoldUpdate(FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE) },
|
{ foldStateProvider.sendUnfoldedScreenAvailable() },
|
||||||
)
|
)
|
||||||
|
|
||||||
with(listener.ensureTransitionFinished()) {
|
with(listener.ensureTransitionFinished()) {
|
||||||
@@ -113,7 +112,7 @@ class PhysicsBasedUnfoldTransitionProgressProviderTest : SysuiTestCase() {
|
|||||||
fun testUnfoldAndStopUnfolding_finishesTheUnfoldTransition() {
|
fun testUnfoldAndStopUnfolding_finishesTheUnfoldTransition() {
|
||||||
runOnMainThreadWithInterval(
|
runOnMainThreadWithInterval(
|
||||||
{ foldStateProvider.sendFoldUpdate(FOLD_UPDATE_START_OPENING) },
|
{ foldStateProvider.sendFoldUpdate(FOLD_UPDATE_START_OPENING) },
|
||||||
{ foldStateProvider.sendFoldUpdate(FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE) },
|
{ foldStateProvider.sendUnfoldedScreenAvailable() },
|
||||||
{ foldStateProvider.sendHingeAngleUpdate(10f) },
|
{ foldStateProvider.sendHingeAngleUpdate(10f) },
|
||||||
{ foldStateProvider.sendHingeAngleUpdate(90f) },
|
{ foldStateProvider.sendHingeAngleUpdate(90f) },
|
||||||
{ foldStateProvider.sendFoldUpdate(FOLD_UPDATE_FINISH_HALF_OPEN) },
|
{ foldStateProvider.sendFoldUpdate(FOLD_UPDATE_FINISH_HALF_OPEN) },
|
||||||
@@ -129,7 +128,7 @@ class PhysicsBasedUnfoldTransitionProgressProviderTest : SysuiTestCase() {
|
|||||||
fun testFoldImmediatelyAfterUnfold_runsFoldAnimation() {
|
fun testFoldImmediatelyAfterUnfold_runsFoldAnimation() {
|
||||||
runOnMainThreadWithInterval(
|
runOnMainThreadWithInterval(
|
||||||
{ foldStateProvider.sendFoldUpdate(FOLD_UPDATE_START_OPENING) },
|
{ foldStateProvider.sendFoldUpdate(FOLD_UPDATE_START_OPENING) },
|
||||||
{ foldStateProvider.sendFoldUpdate(FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE) },
|
{ foldStateProvider.sendUnfoldedScreenAvailable() },
|
||||||
{ foldStateProvider.sendHingeAngleUpdate(10f) },
|
{ foldStateProvider.sendHingeAngleUpdate(10f) },
|
||||||
{ foldStateProvider.sendHingeAngleUpdate(90f) },
|
{ foldStateProvider.sendHingeAngleUpdate(90f) },
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import com.android.systemui.unfold.config.UnfoldTransitionConfig
|
|||||||
import com.android.systemui.unfold.system.ActivityManagerActivityTypeProvider
|
import com.android.systemui.unfold.system.ActivityManagerActivityTypeProvider
|
||||||
import com.android.systemui.unfold.updates.FoldProvider.FoldCallback
|
import com.android.systemui.unfold.updates.FoldProvider.FoldCallback
|
||||||
import com.android.systemui.unfold.updates.RotationChangeProvider.RotationListener
|
import com.android.systemui.unfold.updates.RotationChangeProvider.RotationListener
|
||||||
|
import com.android.systemui.unfold.updates.hinge.FULLY_OPEN_DEGREES
|
||||||
import com.android.systemui.unfold.updates.hinge.HingeAngleProvider
|
import com.android.systemui.unfold.updates.hinge.HingeAngleProvider
|
||||||
import com.android.systemui.unfold.updates.screen.ScreenStatusProvider
|
import com.android.systemui.unfold.updates.screen.ScreenStatusProvider
|
||||||
import com.android.systemui.unfold.updates.screen.ScreenStatusProvider.ScreenListener
|
import com.android.systemui.unfold.updates.screen.ScreenStatusProvider.ScreenListener
|
||||||
@@ -71,6 +72,7 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
|
|||||||
|
|
||||||
private val foldUpdates: MutableList<Int> = arrayListOf()
|
private val foldUpdates: MutableList<Int> = arrayListOf()
|
||||||
private val hingeAngleUpdates: MutableList<Float> = arrayListOf()
|
private val hingeAngleUpdates: MutableList<Float> = arrayListOf()
|
||||||
|
private val unfoldedScreenAvailabilityUpdates: MutableList<Unit> = arrayListOf()
|
||||||
|
|
||||||
private var scheduledRunnable: Runnable? = null
|
private var scheduledRunnable: Runnable? = null
|
||||||
private var scheduledRunnableDelay: Long? = null
|
private var scheduledRunnableDelay: Long? = null
|
||||||
@@ -106,6 +108,10 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
|
|||||||
override fun onFoldUpdate(update: Int) {
|
override fun onFoldUpdate(update: Int) {
|
||||||
foldUpdates.add(update)
|
foldUpdates.add(update)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onUnfoldedScreenAvailable() {
|
||||||
|
unfoldedScreenAvailabilityUpdates.add(Unit)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
foldStateProvider.start()
|
foldStateProvider.start()
|
||||||
|
|
||||||
@@ -156,8 +162,8 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
|
|||||||
sendHingeAngleEvent(10)
|
sendHingeAngleEvent(10)
|
||||||
screenOnStatusProvider.notifyScreenTurnedOn()
|
screenOnStatusProvider.notifyScreenTurnedOn()
|
||||||
|
|
||||||
assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_OPENING,
|
assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_OPENING)
|
||||||
FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE)
|
assertThat(unfoldedScreenAvailabilityUpdates).hasSize(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -174,8 +180,9 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
|
|||||||
sendHingeAngleEvent(40)
|
sendHingeAngleEvent(40)
|
||||||
sendHingeAngleEvent(10)
|
sendHingeAngleEvent(10)
|
||||||
|
|
||||||
assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_OPENING,
|
assertThat(foldUpdates)
|
||||||
FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE, FOLD_UPDATE_START_CLOSING)
|
.containsExactly(FOLD_UPDATE_START_OPENING, FOLD_UPDATE_START_CLOSING)
|
||||||
|
assertThat(unfoldedScreenAvailabilityUpdates).hasSize(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -223,7 +230,7 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
|
|||||||
|
|
||||||
fireScreenOnEvent()
|
fireScreenOnEvent()
|
||||||
|
|
||||||
assertThat(foldUpdates).containsExactly(FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE)
|
assertThat(unfoldedScreenAvailabilityUpdates).hasSize(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -277,7 +284,7 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun startClosingEvent_afterTimeout_finishHalfOpenEventEmitted() {
|
fun startClosingEvent_afterTimeout_finishHalfOpenEventEmitted() {
|
||||||
sendHingeAngleEvent(90)
|
setInitialHingeAngle(90)
|
||||||
sendHingeAngleEvent(80)
|
sendHingeAngleEvent(80)
|
||||||
|
|
||||||
simulateTimeout(HALF_OPENED_TIMEOUT_MILLIS)
|
simulateTimeout(HALF_OPENED_TIMEOUT_MILLIS)
|
||||||
@@ -288,7 +295,7 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun startClosingEvent_beforeTimeout_abortNotEmitted() {
|
fun startClosingEvent_beforeTimeout_abortNotEmitted() {
|
||||||
sendHingeAngleEvent(90)
|
setInitialHingeAngle(90)
|
||||||
sendHingeAngleEvent(80)
|
sendHingeAngleEvent(80)
|
||||||
|
|
||||||
simulateTimeout(HALF_OPENED_TIMEOUT_MILLIS - 1)
|
simulateTimeout(HALF_OPENED_TIMEOUT_MILLIS - 1)
|
||||||
@@ -298,7 +305,7 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun startClosingEvent_eventBeforeTimeout_oneEventEmitted() {
|
fun startClosingEvent_eventBeforeTimeout_oneEventEmitted() {
|
||||||
sendHingeAngleEvent(180)
|
setInitialHingeAngle(180)
|
||||||
sendHingeAngleEvent(90)
|
sendHingeAngleEvent(90)
|
||||||
|
|
||||||
simulateTimeout(HALF_OPENED_TIMEOUT_MILLIS - 1)
|
simulateTimeout(HALF_OPENED_TIMEOUT_MILLIS - 1)
|
||||||
@@ -309,7 +316,7 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun startClosingEvent_timeoutAfterTimeoutRescheduled_finishHalfOpenStateEmitted() {
|
fun startClosingEvent_timeoutAfterTimeoutRescheduled_finishHalfOpenStateEmitted() {
|
||||||
sendHingeAngleEvent(180)
|
setInitialHingeAngle(180)
|
||||||
sendHingeAngleEvent(90)
|
sendHingeAngleEvent(90)
|
||||||
|
|
||||||
// The timeout should not trigger here.
|
// The timeout should not trigger here.
|
||||||
@@ -323,7 +330,7 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun startClosingEvent_shortTimeBetween_emitsOnlyOneEvents() {
|
fun startClosingEvent_shortTimeBetween_emitsOnlyOneEvents() {
|
||||||
sendHingeAngleEvent(180)
|
setInitialHingeAngle(180)
|
||||||
|
|
||||||
sendHingeAngleEvent(90)
|
sendHingeAngleEvent(90)
|
||||||
sendHingeAngleEvent(80)
|
sendHingeAngleEvent(80)
|
||||||
@@ -334,20 +341,19 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
|
|||||||
@Test
|
@Test
|
||||||
fun startClosingEvent_whileClosing_emittedDespiteInitialAngle() {
|
fun startClosingEvent_whileClosing_emittedDespiteInitialAngle() {
|
||||||
val maxAngle = 180 - FULLY_OPEN_THRESHOLD_DEGREES.toInt()
|
val maxAngle = 180 - FULLY_OPEN_THRESHOLD_DEGREES.toInt()
|
||||||
for (i in 1..maxAngle) {
|
val minAngle = Math.ceil(HINGE_ANGLE_CHANGE_THRESHOLD_DEGREES.toDouble()).toInt() + 1
|
||||||
foldUpdates.clear()
|
for (startAngle in minAngle..maxAngle) {
|
||||||
|
setInitialHingeAngle(startAngle)
|
||||||
simulateFolding(startAngle = i)
|
sendHingeAngleEvent(startAngle - HINGE_ANGLE_CHANGE_THRESHOLD_DEGREES.toInt() - 1)
|
||||||
|
|
||||||
assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_CLOSING)
|
assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_CLOSING)
|
||||||
simulateTimeout() // Timeout to set the state to aborted.
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun startClosingEvent_whileNotOnLauncher_doesNotTriggerBeforeThreshold() {
|
fun startClosingEvent_whileNotOnLauncher_doesNotTriggerBeforeThreshold() {
|
||||||
setupForegroundActivityType(isHomeActivity = false)
|
setupForegroundActivityType(isHomeActivity = false)
|
||||||
sendHingeAngleEvent(180)
|
setInitialHingeAngle(180)
|
||||||
|
|
||||||
sendHingeAngleEvent(START_CLOSING_ON_APPS_THRESHOLD_DEGREES + 1)
|
sendHingeAngleEvent(START_CLOSING_ON_APPS_THRESHOLD_DEGREES + 1)
|
||||||
|
|
||||||
@@ -357,7 +363,7 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
|
|||||||
@Test
|
@Test
|
||||||
fun startClosingEvent_whileActivityTypeNotAvailable_triggerBeforeThreshold() {
|
fun startClosingEvent_whileActivityTypeNotAvailable_triggerBeforeThreshold() {
|
||||||
setupForegroundActivityType(isHomeActivity = null)
|
setupForegroundActivityType(isHomeActivity = null)
|
||||||
sendHingeAngleEvent(180)
|
setInitialHingeAngle(180)
|
||||||
|
|
||||||
sendHingeAngleEvent(START_CLOSING_ON_APPS_THRESHOLD_DEGREES + 1)
|
sendHingeAngleEvent(START_CLOSING_ON_APPS_THRESHOLD_DEGREES + 1)
|
||||||
|
|
||||||
@@ -367,7 +373,7 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
|
|||||||
@Test
|
@Test
|
||||||
fun startClosingEvent_whileOnLauncher_doesTriggerBeforeThreshold() {
|
fun startClosingEvent_whileOnLauncher_doesTriggerBeforeThreshold() {
|
||||||
setupForegroundActivityType(isHomeActivity = true)
|
setupForegroundActivityType(isHomeActivity = true)
|
||||||
sendHingeAngleEvent(180)
|
setInitialHingeAngle(180)
|
||||||
|
|
||||||
sendHingeAngleEvent(START_CLOSING_ON_APPS_THRESHOLD_DEGREES + 1)
|
sendHingeAngleEvent(START_CLOSING_ON_APPS_THRESHOLD_DEGREES + 1)
|
||||||
|
|
||||||
@@ -377,9 +383,11 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
|
|||||||
@Test
|
@Test
|
||||||
fun startClosingEvent_whileNotOnLauncher_triggersAfterThreshold() {
|
fun startClosingEvent_whileNotOnLauncher_triggersAfterThreshold() {
|
||||||
setupForegroundActivityType(isHomeActivity = false)
|
setupForegroundActivityType(isHomeActivity = false)
|
||||||
sendHingeAngleEvent(START_CLOSING_ON_APPS_THRESHOLD_DEGREES)
|
setInitialHingeAngle(START_CLOSING_ON_APPS_THRESHOLD_DEGREES)
|
||||||
|
|
||||||
sendHingeAngleEvent(START_CLOSING_ON_APPS_THRESHOLD_DEGREES - 1)
|
sendHingeAngleEvent(
|
||||||
|
START_CLOSING_ON_APPS_THRESHOLD_DEGREES -
|
||||||
|
HINGE_ANGLE_CHANGE_THRESHOLD_DEGREES.toInt() - 1)
|
||||||
|
|
||||||
assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_CLOSING)
|
assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_CLOSING)
|
||||||
}
|
}
|
||||||
@@ -388,7 +396,7 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
|
|||||||
fun startClosingEvent_whileNotOnKeyguardAndNotOnLauncher_doesNotTriggerBeforeThreshold() {
|
fun startClosingEvent_whileNotOnKeyguardAndNotOnLauncher_doesNotTriggerBeforeThreshold() {
|
||||||
setKeyguardVisibility(visible = false)
|
setKeyguardVisibility(visible = false)
|
||||||
setupForegroundActivityType(isHomeActivity = false)
|
setupForegroundActivityType(isHomeActivity = false)
|
||||||
sendHingeAngleEvent(180)
|
setInitialHingeAngle(180)
|
||||||
|
|
||||||
sendHingeAngleEvent(START_CLOSING_ON_APPS_THRESHOLD_DEGREES + 1)
|
sendHingeAngleEvent(START_CLOSING_ON_APPS_THRESHOLD_DEGREES + 1)
|
||||||
|
|
||||||
@@ -398,7 +406,7 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
|
|||||||
@Test
|
@Test
|
||||||
fun startClosingEvent_whileKeyguardStateNotAvailable_triggerBeforeThreshold() {
|
fun startClosingEvent_whileKeyguardStateNotAvailable_triggerBeforeThreshold() {
|
||||||
setKeyguardVisibility(visible = null)
|
setKeyguardVisibility(visible = null)
|
||||||
sendHingeAngleEvent(180)
|
setInitialHingeAngle(180)
|
||||||
|
|
||||||
sendHingeAngleEvent(START_CLOSING_ON_APPS_THRESHOLD_DEGREES + 1)
|
sendHingeAngleEvent(START_CLOSING_ON_APPS_THRESHOLD_DEGREES + 1)
|
||||||
|
|
||||||
@@ -408,7 +416,7 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
|
|||||||
@Test
|
@Test
|
||||||
fun startClosingEvent_whileonKeyguard_doesTriggerBeforeThreshold() {
|
fun startClosingEvent_whileonKeyguard_doesTriggerBeforeThreshold() {
|
||||||
setKeyguardVisibility(visible = true)
|
setKeyguardVisibility(visible = true)
|
||||||
sendHingeAngleEvent(180)
|
setInitialHingeAngle(180)
|
||||||
|
|
||||||
sendHingeAngleEvent(START_CLOSING_ON_APPS_THRESHOLD_DEGREES + 1)
|
sendHingeAngleEvent(START_CLOSING_ON_APPS_THRESHOLD_DEGREES + 1)
|
||||||
|
|
||||||
@@ -418,9 +426,59 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
|
|||||||
@Test
|
@Test
|
||||||
fun startClosingEvent_whileNotOnKeyguard_triggersAfterThreshold() {
|
fun startClosingEvent_whileNotOnKeyguard_triggersAfterThreshold() {
|
||||||
setKeyguardVisibility(visible = false)
|
setKeyguardVisibility(visible = false)
|
||||||
sendHingeAngleEvent(START_CLOSING_ON_APPS_THRESHOLD_DEGREES)
|
setInitialHingeAngle(START_CLOSING_ON_APPS_THRESHOLD_DEGREES)
|
||||||
|
|
||||||
sendHingeAngleEvent(START_CLOSING_ON_APPS_THRESHOLD_DEGREES - 1)
|
sendHingeAngleEvent(
|
||||||
|
START_CLOSING_ON_APPS_THRESHOLD_DEGREES -
|
||||||
|
HINGE_ANGLE_CHANGE_THRESHOLD_DEGREES.toInt() - 1)
|
||||||
|
|
||||||
|
assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_CLOSING)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun startClosingEvent_doesNotTriggerBelowThreshold() {
|
||||||
|
val thresholdAngle = (FULLY_OPEN_DEGREES - FULLY_OPEN_THRESHOLD_DEGREES).toInt()
|
||||||
|
setInitialHingeAngle(180)
|
||||||
|
sendHingeAngleEvent(thresholdAngle + 1)
|
||||||
|
|
||||||
|
assertThat(foldUpdates).isEmpty()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun startClosingEvent_triggersAfterThreshold() {
|
||||||
|
val thresholdAngle = (FULLY_OPEN_DEGREES - FULLY_OPEN_THRESHOLD_DEGREES).toInt()
|
||||||
|
setInitialHingeAngle(180)
|
||||||
|
sendHingeAngleEvent(thresholdAngle + 1)
|
||||||
|
sendHingeAngleEvent(thresholdAngle - 1)
|
||||||
|
|
||||||
|
assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_CLOSING)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun startClosingEvent_triggersAfterThreshold_fromHalfOpen() {
|
||||||
|
setInitialHingeAngle(120)
|
||||||
|
sendHingeAngleEvent((120 - HINGE_ANGLE_CHANGE_THRESHOLD_DEGREES + 1).toInt())
|
||||||
|
assertThat(foldUpdates).isEmpty()
|
||||||
|
sendHingeAngleEvent((120 - HINGE_ANGLE_CHANGE_THRESHOLD_DEGREES - 1).toInt())
|
||||||
|
|
||||||
|
assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_CLOSING)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun startOpeningAndClosingEvents_triggerWithOpenAndClose() {
|
||||||
|
setInitialHingeAngle(120)
|
||||||
|
sendHingeAngleEvent(130)
|
||||||
|
sendHingeAngleEvent(120)
|
||||||
|
assertThat(foldUpdates)
|
||||||
|
.containsExactly(FOLD_UPDATE_START_OPENING, FOLD_UPDATE_START_CLOSING)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun startClosingEvent_notInterrupted_whenAngleIsSlightlyIncreased() {
|
||||||
|
setInitialHingeAngle(120)
|
||||||
|
sendHingeAngleEvent(110)
|
||||||
|
sendHingeAngleEvent(111)
|
||||||
|
sendHingeAngleEvent(100)
|
||||||
|
|
||||||
assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_CLOSING)
|
assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_CLOSING)
|
||||||
}
|
}
|
||||||
@@ -504,11 +562,6 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun simulateFolding(startAngle: Int) {
|
|
||||||
sendHingeAngleEvent(startAngle)
|
|
||||||
sendHingeAngleEvent(startAngle - 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setFoldState(folded: Boolean) {
|
private fun setFoldState(folded: Boolean) {
|
||||||
foldProvider.notifyFolded(folded)
|
foldProvider.notifyFolded(folded)
|
||||||
}
|
}
|
||||||
@@ -521,6 +574,17 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
|
|||||||
testHingeAngleProvider.notifyAngle(angle.toFloat())
|
testHingeAngleProvider.notifyAngle(angle.toFloat())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun setInitialHingeAngle(angle: Int) {
|
||||||
|
setFoldState(angle == 0)
|
||||||
|
sendHingeAngleEvent(angle)
|
||||||
|
if (scheduledRunnableDelay != null) {
|
||||||
|
simulateTimeout()
|
||||||
|
}
|
||||||
|
hingeAngleUpdates.clear()
|
||||||
|
foldUpdates.clear()
|
||||||
|
unfoldedScreenAvailabilityUpdates.clear()
|
||||||
|
}
|
||||||
|
|
||||||
private class TestFoldProvider : FoldProvider {
|
private class TestFoldProvider : FoldProvider {
|
||||||
private val callbacks = arrayListOf<FoldCallback>()
|
private val callbacks = arrayListOf<FoldCallback>()
|
||||||
|
|
||||||
|
|||||||
@@ -57,4 +57,8 @@ class TestFoldStateProvider : FoldStateProvider {
|
|||||||
fun sendHingeAngleUpdate(angle: Float) {
|
fun sendHingeAngleUpdate(angle: Float) {
|
||||||
listeners.forEach { it.onHingeAngleUpdate(angle) }
|
listeners.forEach { it.onHingeAngleUpdate(angle) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun sendUnfoldedScreenAvailable() {
|
||||||
|
listeners.forEach { it.onUnfoldedScreenAvailable() }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ import android.util.FloatProperty
|
|||||||
import com.android.systemui.unfold.UnfoldTransitionProgressProvider
|
import com.android.systemui.unfold.UnfoldTransitionProgressProvider
|
||||||
import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
|
import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
|
||||||
import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_CLOSED
|
import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_CLOSED
|
||||||
import com.android.systemui.unfold.updates.FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE
|
|
||||||
import com.android.systemui.unfold.updates.FoldStateProvider
|
import com.android.systemui.unfold.updates.FoldStateProvider
|
||||||
import com.android.systemui.unfold.updates.FoldStateProvider.FoldUpdate
|
import com.android.systemui.unfold.updates.FoldStateProvider.FoldUpdate
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@@ -59,12 +58,15 @@ constructor(private val foldStateProvider: FoldStateProvider) :
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onFoldUpdate(@FoldUpdate update: Int) {
|
override fun onFoldUpdate(@FoldUpdate update: Int) {
|
||||||
when (update) {
|
if (update == FOLD_UPDATE_FINISH_CLOSED) {
|
||||||
FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE -> animator.start()
|
animator.cancel()
|
||||||
FOLD_UPDATE_FINISH_CLOSED -> animator.cancel()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onUnfoldedScreenAvailable() {
|
||||||
|
animator.start()
|
||||||
|
}
|
||||||
|
|
||||||
override fun addCallback(listener: TransitionProgressListener) {
|
override fun addCallback(listener: TransitionProgressListener) {
|
||||||
listeners.add(listener)
|
listeners.add(listener)
|
||||||
}
|
}
|
||||||
@@ -73,8 +75,6 @@ constructor(private val foldStateProvider: FoldStateProvider) :
|
|||||||
listeners.remove(listener)
|
listeners.remove(listener)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onHingeAngleUpdate(angle: Float) {}
|
|
||||||
|
|
||||||
private object AnimationProgressProperty :
|
private object AnimationProgressProperty :
|
||||||
FloatProperty<FixedTimingTransitionProgressProvider>("animation_progress") {
|
FloatProperty<FixedTimingTransitionProgressProvider>("animation_progress") {
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_CLOSED
|
|||||||
import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_FULL_OPEN
|
import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_FULL_OPEN
|
||||||
import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_HALF_OPEN
|
import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_HALF_OPEN
|
||||||
import com.android.systemui.unfold.updates.FOLD_UPDATE_START_CLOSING
|
import com.android.systemui.unfold.updates.FOLD_UPDATE_START_CLOSING
|
||||||
import com.android.systemui.unfold.updates.FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE
|
|
||||||
import com.android.systemui.unfold.updates.FoldStateProvider
|
import com.android.systemui.unfold.updates.FoldStateProvider
|
||||||
import com.android.systemui.unfold.updates.FoldStateProvider.FoldUpdate
|
import com.android.systemui.unfold.updates.FoldStateProvider.FoldUpdate
|
||||||
import com.android.systemui.unfold.updates.FoldStateProvider.FoldUpdatesListener
|
import com.android.systemui.unfold.updates.FoldStateProvider.FoldUpdatesListener
|
||||||
@@ -78,21 +77,11 @@ class PhysicsBasedUnfoldTransitionProgressProvider @Inject constructor(
|
|||||||
|
|
||||||
override fun onFoldUpdate(@FoldUpdate update: Int) {
|
override fun onFoldUpdate(@FoldUpdate update: Int) {
|
||||||
when (update) {
|
when (update) {
|
||||||
FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE -> {
|
|
||||||
startTransition(startValue = 0f)
|
|
||||||
|
|
||||||
// Stop the animation if the device has already opened by the time when
|
|
||||||
// the display is available as we won't receive the full open event anymore
|
|
||||||
if (foldStateProvider.isFinishedOpening) {
|
|
||||||
cancelTransition(endValue = 1f, animate = true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
FOLD_UPDATE_FINISH_FULL_OPEN, FOLD_UPDATE_FINISH_HALF_OPEN -> {
|
FOLD_UPDATE_FINISH_FULL_OPEN, FOLD_UPDATE_FINISH_HALF_OPEN -> {
|
||||||
// Do not cancel if we haven't started the transition yet.
|
// Do not cancel if we haven't started the transition yet.
|
||||||
// This could happen when we fully unfolded the device before the screen
|
// This could happen when we fully unfolded the device before the screen
|
||||||
// became available. In this case we start and immediately cancel the animation
|
// became available. In this case we start and immediately cancel the animation
|
||||||
// in FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE event handler, so we don't need to
|
// in onUnfoldedScreenAvailable event handler, so we don't need to cancel it here.
|
||||||
// cancel it here.
|
|
||||||
if (isTransitionRunning) {
|
if (isTransitionRunning) {
|
||||||
cancelTransition(endValue = 1f, animate = true)
|
cancelTransition(endValue = 1f, animate = true)
|
||||||
}
|
}
|
||||||
@@ -125,6 +114,16 @@ class PhysicsBasedUnfoldTransitionProgressProvider @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onUnfoldedScreenAvailable() {
|
||||||
|
startTransition(startValue = 0f)
|
||||||
|
|
||||||
|
// Stop the animation if the device has already opened by the time when
|
||||||
|
// the display is available as we won't receive the full open event anymore
|
||||||
|
if (foldStateProvider.isFinishedOpening) {
|
||||||
|
cancelTransition(endValue = 1f, animate = true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun cancelTransition(endValue: Float, animate: Boolean) {
|
private fun cancelTransition(endValue: Float, animate: Boolean) {
|
||||||
if (isTransitionRunning && animate) {
|
if (isTransitionRunning && animate) {
|
||||||
if (endValue == 1.0f && !isAnimatedCancelRunning) {
|
if (endValue == 1.0f && !isAnimatedCancelRunning) {
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ constructor(
|
|||||||
@FoldUpdate private var lastFoldUpdate: Int? = null
|
@FoldUpdate private var lastFoldUpdate: Int? = null
|
||||||
|
|
||||||
@FloatRange(from = 0.0, to = 180.0) private var lastHingeAngle: Float = 0f
|
@FloatRange(from = 0.0, to = 180.0) private var lastHingeAngle: Float = 0f
|
||||||
|
@FloatRange(from = 0.0, to = 180.0) private var lastHingeAngleBeforeTransition: Float = 0f
|
||||||
|
|
||||||
private val hingeAngleListener = HingeAngleListener()
|
private val hingeAngleListener = HingeAngleListener()
|
||||||
private val screenListener = ScreenStatusListener()
|
private val screenListener = ScreenStatusListener()
|
||||||
@@ -112,29 +113,45 @@ constructor(
|
|||||||
|
|
||||||
private fun onHingeAngle(angle: Float) {
|
private fun onHingeAngle(angle: Float) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.d(TAG, "Hinge angle: $angle, lastHingeAngle: $lastHingeAngle")
|
Log.d(
|
||||||
|
TAG,
|
||||||
|
"Hinge angle: $angle, " +
|
||||||
|
"lastHingeAngle: $lastHingeAngle, " +
|
||||||
|
"lastHingeAngleBeforeTransition: $lastHingeAngleBeforeTransition"
|
||||||
|
)
|
||||||
Trace.traceCounter(Trace.TRACE_TAG_APP, "hinge_angle", angle.toInt())
|
Trace.traceCounter(Trace.TRACE_TAG_APP, "hinge_angle", angle.toInt())
|
||||||
}
|
}
|
||||||
|
|
||||||
val isClosing = angle < lastHingeAngle
|
val currentDirection =
|
||||||
|
if (angle < lastHingeAngle) FOLD_UPDATE_START_CLOSING else FOLD_UPDATE_START_OPENING
|
||||||
|
if (isTransitionInProgress && currentDirection != lastFoldUpdate) {
|
||||||
|
lastHingeAngleBeforeTransition = lastHingeAngle
|
||||||
|
}
|
||||||
|
|
||||||
|
val isClosing = angle < lastHingeAngleBeforeTransition
|
||||||
|
val transitionUpdate =
|
||||||
|
if (isClosing) FOLD_UPDATE_START_CLOSING else FOLD_UPDATE_START_OPENING
|
||||||
|
val angleChangeSurpassedThreshold =
|
||||||
|
Math.abs(angle - lastHingeAngleBeforeTransition) > HINGE_ANGLE_CHANGE_THRESHOLD_DEGREES
|
||||||
val isFullyOpened = FULLY_OPEN_DEGREES - angle < FULLY_OPEN_THRESHOLD_DEGREES
|
val isFullyOpened = FULLY_OPEN_DEGREES - angle < FULLY_OPEN_THRESHOLD_DEGREES
|
||||||
val closingEventDispatched = lastFoldUpdate == FOLD_UPDATE_START_CLOSING
|
val eventNotAlreadyDispatched = lastFoldUpdate != transitionUpdate
|
||||||
val screenAvailableEventSent = isUnfoldHandled
|
val screenAvailableEventSent = isUnfoldHandled
|
||||||
|
|
||||||
if (isClosing // hinge angle should be decreasing since last update
|
if (
|
||||||
&& !closingEventDispatched // we haven't sent closing event already
|
angleChangeSurpassedThreshold && // Do not react immediately to small changes in angle
|
||||||
&& !isFullyOpened // do not send closing event if we are in fully opened hinge
|
eventNotAlreadyDispatched && // we haven't sent transition event already
|
||||||
|
!isFullyOpened && // do not send transition event if we are in fully opened hinge
|
||||||
// angle range as closing threshold could overlap this range
|
// angle range as closing threshold could overlap this range
|
||||||
&& screenAvailableEventSent // do not send closing event if we are still in
|
screenAvailableEventSent && // do not send transition event if we are still in the
|
||||||
// the process of turning on the inner display
|
// process of turning on the inner display
|
||||||
&& isClosingThresholdMet(angle) // hinge angle is below certain threshold.
|
isClosingThresholdMet(angle) // hinge angle is below certain threshold.
|
||||||
) {
|
) {
|
||||||
notifyFoldUpdate(FOLD_UPDATE_START_CLOSING)
|
notifyFoldUpdate(transitionUpdate, lastHingeAngle)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isTransitionInProgress) {
|
if (isTransitionInProgress) {
|
||||||
if (isFullyOpened) {
|
if (isFullyOpened) {
|
||||||
notifyFoldUpdate(FOLD_UPDATE_FINISH_FULL_OPEN)
|
notifyFoldUpdate(FOLD_UPDATE_FINISH_FULL_OPEN, angle)
|
||||||
cancelTimeout()
|
cancelTimeout()
|
||||||
} else {
|
} else {
|
||||||
// The timeout will trigger some constant time after the last angle update.
|
// The timeout will trigger some constant time after the last angle update.
|
||||||
@@ -146,7 +163,7 @@ constructor(
|
|||||||
outputListeners.forEach { it.onHingeAngleUpdate(angle) }
|
outputListeners.forEach { it.onHingeAngleUpdate(angle) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isClosingThresholdMet(currentAngle: Float) : Boolean {
|
private fun isClosingThresholdMet(currentAngle: Float): Boolean {
|
||||||
val closingThreshold = getClosingThreshold()
|
val closingThreshold = getClosingThreshold()
|
||||||
return closingThreshold == null || currentAngle < closingThreshold
|
return closingThreshold == null || currentAngle < closingThreshold
|
||||||
}
|
}
|
||||||
@@ -179,23 +196,29 @@ constructor(
|
|||||||
|
|
||||||
if (isFolded) {
|
if (isFolded) {
|
||||||
hingeAngleProvider.stop()
|
hingeAngleProvider.stop()
|
||||||
notifyFoldUpdate(FOLD_UPDATE_FINISH_CLOSED)
|
notifyFoldUpdate(FOLD_UPDATE_FINISH_CLOSED, lastHingeAngle)
|
||||||
cancelTimeout()
|
cancelTimeout()
|
||||||
isUnfoldHandled = false
|
isUnfoldHandled = false
|
||||||
} else {
|
} else {
|
||||||
notifyFoldUpdate(FOLD_UPDATE_START_OPENING)
|
notifyFoldUpdate(FOLD_UPDATE_START_OPENING, lastHingeAngle)
|
||||||
rescheduleAbortAnimationTimeout()
|
rescheduleAbortAnimationTimeout()
|
||||||
hingeAngleProvider.start()
|
hingeAngleProvider.start()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun notifyFoldUpdate(@FoldUpdate update: Int) {
|
private fun notifyFoldUpdate(@FoldUpdate update: Int, angle: Float) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.d(TAG, update.name())
|
Log.d(TAG, update.name())
|
||||||
}
|
}
|
||||||
|
val previouslyTransitioning = isTransitionInProgress
|
||||||
|
|
||||||
outputListeners.forEach { it.onFoldUpdate(update) }
|
outputListeners.forEach { it.onFoldUpdate(update) }
|
||||||
lastFoldUpdate = update
|
lastFoldUpdate = update
|
||||||
|
|
||||||
|
if (previouslyTransitioning != isTransitionInProgress) {
|
||||||
|
lastHingeAngleBeforeTransition = angle
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun rescheduleAbortAnimationTimeout() {
|
private fun rescheduleAbortAnimationTimeout() {
|
||||||
@@ -209,7 +232,8 @@ constructor(
|
|||||||
handler.removeCallbacks(timeoutRunnable)
|
handler.removeCallbacks(timeoutRunnable)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun cancelAnimation(): Unit = notifyFoldUpdate(FOLD_UPDATE_FINISH_HALF_OPEN)
|
private fun cancelAnimation(): Unit =
|
||||||
|
notifyFoldUpdate(FOLD_UPDATE_FINISH_HALF_OPEN, lastHingeAngle)
|
||||||
|
|
||||||
private inner class ScreenStatusListener : ScreenStatusProvider.ScreenListener {
|
private inner class ScreenStatusListener : ScreenStatusProvider.ScreenListener {
|
||||||
|
|
||||||
@@ -221,7 +245,7 @@ constructor(
|
|||||||
// receive 'folded' event. If SystemUI started when device is already folded it will
|
// receive 'folded' event. If SystemUI started when device is already folded it will
|
||||||
// still receive 'folded' event on startup.
|
// still receive 'folded' event on startup.
|
||||||
if (!isFolded && !isUnfoldHandled) {
|
if (!isFolded && !isUnfoldHandled) {
|
||||||
outputListeners.forEach { it.onFoldUpdate(FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE) }
|
outputListeners.forEach { it.onUnfoldedScreenAvailable() }
|
||||||
isUnfoldHandled = true
|
isUnfoldHandled = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -257,7 +281,6 @@ fun @receiver:FoldUpdate Int.name() =
|
|||||||
when (this) {
|
when (this) {
|
||||||
FOLD_UPDATE_START_OPENING -> "START_OPENING"
|
FOLD_UPDATE_START_OPENING -> "START_OPENING"
|
||||||
FOLD_UPDATE_START_CLOSING -> "START_CLOSING"
|
FOLD_UPDATE_START_CLOSING -> "START_CLOSING"
|
||||||
FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE -> "UNFOLDED_SCREEN_AVAILABLE"
|
|
||||||
FOLD_UPDATE_FINISH_HALF_OPEN -> "FINISH_HALF_OPEN"
|
FOLD_UPDATE_FINISH_HALF_OPEN -> "FINISH_HALF_OPEN"
|
||||||
FOLD_UPDATE_FINISH_FULL_OPEN -> "FINISH_FULL_OPEN"
|
FOLD_UPDATE_FINISH_FULL_OPEN -> "FINISH_FULL_OPEN"
|
||||||
FOLD_UPDATE_FINISH_CLOSED -> "FINISH_CLOSED"
|
FOLD_UPDATE_FINISH_CLOSED -> "FINISH_CLOSED"
|
||||||
@@ -270,5 +293,8 @@ private val DEBUG = Log.isLoggable(TAG, Log.DEBUG)
|
|||||||
/** Threshold after which we consider the device fully unfolded. */
|
/** Threshold after which we consider the device fully unfolded. */
|
||||||
@VisibleForTesting const val FULLY_OPEN_THRESHOLD_DEGREES = 15f
|
@VisibleForTesting const val FULLY_OPEN_THRESHOLD_DEGREES = 15f
|
||||||
|
|
||||||
|
/** Threshold after which hinge angle updates are considered. This is to eliminate noise. */
|
||||||
|
@VisibleForTesting const val HINGE_ANGLE_CHANGE_THRESHOLD_DEGREES = 7.5f
|
||||||
|
|
||||||
/** Fold animation on top of apps only when the angle exceeds this threshold. */
|
/** Fold animation on top of apps only when the angle exceeds this threshold. */
|
||||||
@VisibleForTesting const val START_CLOSING_ON_APPS_THRESHOLD_DEGREES = 60
|
@VisibleForTesting const val START_CLOSING_ON_APPS_THRESHOLD_DEGREES = 60
|
||||||
|
|||||||
@@ -31,8 +31,9 @@ interface FoldStateProvider : CallbackController<FoldUpdatesListener> {
|
|||||||
val isFinishedOpening: Boolean
|
val isFinishedOpening: Boolean
|
||||||
|
|
||||||
interface FoldUpdatesListener {
|
interface FoldUpdatesListener {
|
||||||
fun onHingeAngleUpdate(@FloatRange(from = 0.0, to = 180.0) angle: Float)
|
@JvmDefault fun onHingeAngleUpdate(@FloatRange(from = 0.0, to = 180.0) angle: Float) {}
|
||||||
fun onFoldUpdate(@FoldUpdate update: Int)
|
@JvmDefault fun onFoldUpdate(@FoldUpdate update: Int) {}
|
||||||
|
@JvmDefault fun onUnfoldedScreenAvailable() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@IntDef(
|
@IntDef(
|
||||||
@@ -40,7 +41,6 @@ interface FoldStateProvider : CallbackController<FoldUpdatesListener> {
|
|||||||
[
|
[
|
||||||
FOLD_UPDATE_START_OPENING,
|
FOLD_UPDATE_START_OPENING,
|
||||||
FOLD_UPDATE_START_CLOSING,
|
FOLD_UPDATE_START_CLOSING,
|
||||||
FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE,
|
|
||||||
FOLD_UPDATE_FINISH_HALF_OPEN,
|
FOLD_UPDATE_FINISH_HALF_OPEN,
|
||||||
FOLD_UPDATE_FINISH_FULL_OPEN,
|
FOLD_UPDATE_FINISH_FULL_OPEN,
|
||||||
FOLD_UPDATE_FINISH_CLOSED])
|
FOLD_UPDATE_FINISH_CLOSED])
|
||||||
@@ -50,7 +50,6 @@ interface FoldStateProvider : CallbackController<FoldUpdatesListener> {
|
|||||||
|
|
||||||
const val FOLD_UPDATE_START_OPENING = 0
|
const val FOLD_UPDATE_START_OPENING = 0
|
||||||
const val FOLD_UPDATE_START_CLOSING = 1
|
const val FOLD_UPDATE_START_CLOSING = 1
|
||||||
const val FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE = 2
|
const val FOLD_UPDATE_FINISH_HALF_OPEN = 2
|
||||||
const val FOLD_UPDATE_FINISH_HALF_OPEN = 3
|
const val FOLD_UPDATE_FINISH_FULL_OPEN = 3
|
||||||
const val FOLD_UPDATE_FINISH_FULL_OPEN = 4
|
const val FOLD_UPDATE_FINISH_CLOSED = 4
|
||||||
const val FOLD_UPDATE_FINISH_CLOSED = 5
|
|
||||||
|
|||||||
Reference in New Issue
Block a user