Merge "Create FoldStateLoggingProvider"
This commit is contained in:
committed by
Android (Google) Code Review
commit
edd5a0747a
@@ -21,24 +21,24 @@ import android.content.Context
|
||||
import android.hardware.SensorManager
|
||||
import android.hardware.devicestate.DeviceStateManager
|
||||
import android.os.Handler
|
||||
import com.android.systemui.unfold.updates.screen.ScreenStatusProvider
|
||||
import com.android.systemui.unfold.config.ResourceUnfoldTransitionConfig
|
||||
import com.android.systemui.unfold.config.UnfoldTransitionConfig
|
||||
import com.android.systemui.unfold.progress.FixedTimingTransitionProgressProvider
|
||||
import com.android.systemui.unfold.progress.PhysicsBasedUnfoldTransitionProgressProvider
|
||||
import com.android.systemui.unfold.util.ScaleAwareTransitionProgressProvider
|
||||
import com.android.systemui.unfold.updates.DeviceFoldStateProvider
|
||||
import com.android.systemui.unfold.updates.FoldStateProvider
|
||||
import com.android.systemui.unfold.updates.hinge.EmptyHingeAngleProvider
|
||||
import com.android.systemui.unfold.updates.hinge.HingeSensorAngleProvider
|
||||
import com.android.systemui.unfold.updates.screen.ScreenStatusProvider
|
||||
import com.android.systemui.unfold.util.ATraceLoggerTransitionProgressListener
|
||||
import java.lang.IllegalStateException
|
||||
import com.android.systemui.unfold.util.ScaleAwareTransitionProgressProvider
|
||||
import java.util.concurrent.Executor
|
||||
|
||||
/**
|
||||
* Factory for [UnfoldTransitionProgressProvider].
|
||||
*
|
||||
* This is needed as Launcher has to create the object manually.
|
||||
* Sysui create it using dagger (see [UnfoldTransitionModule]).
|
||||
* This is needed as Launcher has to create the object manually. Sysui create it using dagger (see
|
||||
* [UnfoldTransitionModule]).
|
||||
*/
|
||||
fun createUnfoldTransitionProgressProvider(
|
||||
context: Context,
|
||||
@@ -52,10 +52,45 @@ fun createUnfoldTransitionProgressProvider(
|
||||
): UnfoldTransitionProgressProvider {
|
||||
|
||||
if (!config.isEnabled) {
|
||||
throw IllegalStateException("Trying to create " +
|
||||
"UnfoldTransitionProgressProvider when the transition is disabled")
|
||||
throw IllegalStateException(
|
||||
"Trying to create " +
|
||||
"UnfoldTransitionProgressProvider when the transition is disabled")
|
||||
}
|
||||
|
||||
val foldStateProvider =
|
||||
createFoldStateProvider(
|
||||
context,
|
||||
config,
|
||||
screenStatusProvider,
|
||||
deviceStateManager,
|
||||
sensorManager,
|
||||
mainHandler,
|
||||
mainExecutor)
|
||||
|
||||
val unfoldTransitionProgressProvider =
|
||||
if (config.isHingeAngleEnabled) {
|
||||
PhysicsBasedUnfoldTransitionProgressProvider(foldStateProvider)
|
||||
} else {
|
||||
FixedTimingTransitionProgressProvider(foldStateProvider)
|
||||
}
|
||||
|
||||
return ScaleAwareTransitionProgressProvider(
|
||||
unfoldTransitionProgressProvider, context.contentResolver)
|
||||
.apply {
|
||||
// Always present callback that logs animation beginning and end.
|
||||
addCallback(ATraceLoggerTransitionProgressListener(tracingTagPrefix))
|
||||
}
|
||||
}
|
||||
|
||||
fun createFoldStateProvider(
|
||||
context: Context,
|
||||
config: UnfoldTransitionConfig,
|
||||
screenStatusProvider: ScreenStatusProvider,
|
||||
deviceStateManager: DeviceStateManager,
|
||||
sensorManager: SensorManager,
|
||||
mainHandler: Handler,
|
||||
mainExecutor: Executor
|
||||
): FoldStateProvider {
|
||||
val hingeAngleProvider =
|
||||
if (config.isHingeAngleEnabled) {
|
||||
HingeSensorAngleProvider(sensorManager)
|
||||
@@ -63,28 +98,13 @@ fun createUnfoldTransitionProgressProvider(
|
||||
EmptyHingeAngleProvider()
|
||||
}
|
||||
|
||||
val foldStateProvider = DeviceFoldStateProvider(
|
||||
return DeviceFoldStateProvider(
|
||||
context,
|
||||
hingeAngleProvider,
|
||||
screenStatusProvider,
|
||||
deviceStateManager,
|
||||
mainExecutor,
|
||||
mainHandler
|
||||
)
|
||||
|
||||
val unfoldTransitionProgressProvider = if (config.isHingeAngleEnabled) {
|
||||
PhysicsBasedUnfoldTransitionProgressProvider(foldStateProvider)
|
||||
} else {
|
||||
FixedTimingTransitionProgressProvider(foldStateProvider)
|
||||
}
|
||||
return ScaleAwareTransitionProgressProvider(
|
||||
unfoldTransitionProgressProvider,
|
||||
context.contentResolver
|
||||
).apply {
|
||||
// Always present callback that logs animation beginning and end.
|
||||
addCallback(ATraceLoggerTransitionProgressListener(tracingTagPrefix))
|
||||
}
|
||||
mainHandler)
|
||||
}
|
||||
|
||||
fun createConfig(context: Context): UnfoldTransitionConfig =
|
||||
ResourceUnfoldTransitionConfig(context)
|
||||
fun createConfig(context: Context): UnfoldTransitionConfig = ResourceUnfoldTransitionConfig(context)
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.unfold
|
||||
|
||||
import android.annotation.IntDef
|
||||
import com.android.systemui.statusbar.policy.CallbackController
|
||||
import com.android.systemui.unfold.FoldStateLoggingProvider.FoldStateLoggingListener
|
||||
import com.android.systemui.unfold.FoldStateLoggingProvider.LoggedFoldedStates
|
||||
|
||||
/** Reports device fold states for logging purposes. */
|
||||
// TODO(b/198305865): Log state changes.
|
||||
interface FoldStateLoggingProvider : CallbackController<FoldStateLoggingListener> {
|
||||
|
||||
fun init()
|
||||
fun uninit()
|
||||
|
||||
interface FoldStateLoggingListener {
|
||||
fun onFoldUpdate(foldStateUpdate: FoldStateChange)
|
||||
}
|
||||
|
||||
@IntDef(prefix = ["LOGGED_FOLD_STATE_"], value = [FULLY_OPENED, FULLY_CLOSED, HALF_OPENED])
|
||||
@Retention(AnnotationRetention.SOURCE)
|
||||
annotation class LoggedFoldedStates
|
||||
}
|
||||
|
||||
data class FoldStateChange(
|
||||
@LoggedFoldedStates val previous: Int,
|
||||
@LoggedFoldedStates val current: Int,
|
||||
val dtMillis: Long
|
||||
)
|
||||
|
||||
const val FULLY_OPENED = 1
|
||||
const val FULLY_CLOSED = 2
|
||||
const val HALF_OPENED = 3
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.unfold
|
||||
|
||||
import android.util.Log
|
||||
import com.android.systemui.unfold.FoldStateLoggingProvider.FoldStateLoggingListener
|
||||
import com.android.systemui.unfold.FoldStateLoggingProvider.LoggedFoldedStates
|
||||
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_HALF_OPEN
|
||||
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.FoldStateProvider
|
||||
import com.android.systemui.unfold.updates.FoldStateProvider.FoldUpdate
|
||||
import com.android.systemui.util.time.SystemClock
|
||||
|
||||
/**
|
||||
* Reports device fold states for logging purposes.
|
||||
*
|
||||
* Wraps the state provided by [FoldStateProvider] to output only [FULLY_OPENED], [FULLY_CLOSED] and
|
||||
* [HALF_OPENED] for logging purposes.
|
||||
*
|
||||
* Note that [HALF_OPENED] state is only emitted after the device angle is stable for some timeout.
|
||||
* Check [FoldStateProvider] impl for it.
|
||||
*
|
||||
* This doesn't log the following transitions:
|
||||
* - [HALF_OPENED] -> [FULLY_OPENED]: not interesting, as there is no transition going on
|
||||
* - [HALF_OPENED] -> [HALF_OPENED]: not meaningful.
|
||||
*/
|
||||
class FoldStateLoggingProviderImpl(
|
||||
private val foldStateProvider: FoldStateProvider,
|
||||
private val clock: SystemClock
|
||||
) : FoldStateLoggingProvider, FoldStateProvider.FoldUpdatesListener {
|
||||
|
||||
private val outputListeners: MutableList<FoldStateLoggingListener> = mutableListOf()
|
||||
|
||||
@LoggedFoldedStates private var lastState: Int? = null
|
||||
private var actionStartMillis: Long? = null
|
||||
|
||||
override fun init() {
|
||||
foldStateProvider.addCallback(this)
|
||||
foldStateProvider.start()
|
||||
}
|
||||
|
||||
override fun uninit() {
|
||||
foldStateProvider.removeCallback(this)
|
||||
foldStateProvider.stop()
|
||||
}
|
||||
|
||||
override fun onHingeAngleUpdate(angle: Float) {}
|
||||
|
||||
override fun onFoldUpdate(@FoldUpdate update: Int) {
|
||||
val now = clock.elapsedRealtime()
|
||||
when (update) {
|
||||
FOLD_UPDATE_START_OPENING -> {
|
||||
lastState = FULLY_CLOSED
|
||||
actionStartMillis = now
|
||||
}
|
||||
FOLD_UPDATE_START_CLOSING -> actionStartMillis = now
|
||||
FOLD_UPDATE_FINISH_HALF_OPEN -> dispatchState(HALF_OPENED)
|
||||
FOLD_UPDATE_FINISH_FULL_OPEN -> dispatchState(FULLY_OPENED)
|
||||
FOLD_UPDATE_FINISH_CLOSED -> dispatchState(FULLY_CLOSED)
|
||||
}
|
||||
}
|
||||
|
||||
private fun dispatchState(@LoggedFoldedStates current: Int) {
|
||||
val now = clock.elapsedRealtime()
|
||||
val previous = lastState
|
||||
val lastActionStart = actionStartMillis
|
||||
|
||||
if (previous != null && previous != current && lastActionStart != null) {
|
||||
val time = now - lastActionStart
|
||||
val foldStateChange = FoldStateChange(previous, current, time)
|
||||
outputListeners.forEach { it.onFoldUpdate(foldStateChange) }
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "From $previous to $current in $time")
|
||||
}
|
||||
}
|
||||
|
||||
actionStartMillis = null
|
||||
lastState = current
|
||||
}
|
||||
|
||||
override fun addCallback(listener: FoldStateLoggingListener) {
|
||||
outputListeners.add(listener)
|
||||
}
|
||||
|
||||
override fun removeCallback(listener: FoldStateLoggingListener) {
|
||||
outputListeners.remove(listener)
|
||||
}
|
||||
}
|
||||
|
||||
private const val DEBUG = false
|
||||
private const val TAG = "FoldStateLoggingProviderImpl"
|
||||
@@ -17,10 +17,11 @@
|
||||
package com.android.systemui.unfold
|
||||
|
||||
import com.android.keyguard.KeyguardUnfoldTransition
|
||||
import com.android.systemui.unfold.util.NaturalRotationUnfoldProgressProvider
|
||||
import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.statusbar.phone.StatusBarMoveFromCenterAnimationController
|
||||
import com.android.systemui.unfold.util.NaturalRotationUnfoldProgressProvider
|
||||
import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider
|
||||
import com.android.systemui.util.kotlin.getOrNull
|
||||
import dagger.BindsInstance
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
@@ -36,15 +37,17 @@ annotation class SysUIUnfoldScope
|
||||
|
||||
/**
|
||||
* Creates an injectable [SysUIUnfoldComponent] that provides objects that have been scoped with
|
||||
* [@SysUIUnfoldScope]. Since [SysUIUnfoldComponent] depends upon:
|
||||
* [@SysUIUnfoldScope].
|
||||
*
|
||||
* Since [SysUIUnfoldComponent] depends upon:
|
||||
* * [Optional<UnfoldTransitionProgressProvider>]
|
||||
* * [Optional<ScopedUnfoldTransitionProgressProvider>]
|
||||
* * [Optional<NaturalRotationProgressProvider>]
|
||||
*
|
||||
* no objects will get constructed if these parameters are empty.
|
||||
*/
|
||||
@Module(subcomponents = [SysUIUnfoldComponent::class])
|
||||
class SysUIUnfoldModule {
|
||||
constructor() {}
|
||||
|
||||
@Provides
|
||||
@SysUISingleton
|
||||
@@ -53,12 +56,16 @@ class SysUIUnfoldModule {
|
||||
rotationProvider: Optional<NaturalRotationUnfoldProgressProvider>,
|
||||
@Named(UNFOLD_STATUS_BAR) scopedProvider: Optional<ScopedUnfoldTransitionProgressProvider>,
|
||||
factory: SysUIUnfoldComponent.Factory
|
||||
) =
|
||||
provider.flatMap { p1 ->
|
||||
rotationProvider.flatMap { p2 ->
|
||||
scopedProvider.map { p3 -> factory.create(p1, p2, p3) }
|
||||
}
|
||||
): Optional<SysUIUnfoldComponent> {
|
||||
val p1 = provider.getOrNull()
|
||||
val p2 = rotationProvider.getOrNull()
|
||||
val p3 = scopedProvider.getOrNull()
|
||||
return if (p1 == null || p2 == null || p3 == null) {
|
||||
Optional.empty()
|
||||
} else {
|
||||
Optional.of(factory.create(p1, p2, p3))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SysUIUnfoldScope
|
||||
|
||||
@@ -24,8 +24,10 @@ import android.view.IWindowManager
|
||||
import com.android.systemui.dagger.qualifiers.Main
|
||||
import com.android.systemui.keyguard.LifecycleScreenStatusProvider
|
||||
import com.android.systemui.unfold.config.UnfoldTransitionConfig
|
||||
import com.android.systemui.unfold.updates.FoldStateProvider
|
||||
import com.android.systemui.unfold.util.NaturalRotationUnfoldProgressProvider
|
||||
import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider
|
||||
import com.android.systemui.util.time.SystemClockImpl
|
||||
import com.android.wm.shell.unfold.ShellUnfoldProgressProvider
|
||||
import dagger.Lazy
|
||||
import dagger.Module
|
||||
@@ -48,7 +50,7 @@ class UnfoldTransitionModule {
|
||||
sensorManager: SensorManager,
|
||||
@Main executor: Executor,
|
||||
@Main handler: Handler
|
||||
) =
|
||||
): Optional<UnfoldTransitionProgressProvider> =
|
||||
if (config.isEnabled) {
|
||||
Optional.of(
|
||||
createUnfoldTransitionProgressProvider(
|
||||
@@ -59,13 +61,45 @@ class UnfoldTransitionModule {
|
||||
sensorManager,
|
||||
handler,
|
||||
executor,
|
||||
tracingTagPrefix = "systemui"
|
||||
)
|
||||
)
|
||||
tracingTagPrefix = "systemui"))
|
||||
} else {
|
||||
Optional.empty()
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideFoldStateProvider(
|
||||
context: Context,
|
||||
config: UnfoldTransitionConfig,
|
||||
screenStatusProvider: Lazy<LifecycleScreenStatusProvider>,
|
||||
deviceStateManager: DeviceStateManager,
|
||||
sensorManager: SensorManager,
|
||||
@Main executor: Executor,
|
||||
@Main handler: Handler
|
||||
): Optional<FoldStateProvider> =
|
||||
if (!config.isHingeAngleEnabled) {
|
||||
Optional.empty()
|
||||
} else {
|
||||
Optional.of(
|
||||
createFoldStateProvider(
|
||||
context,
|
||||
config,
|
||||
screenStatusProvider.get(),
|
||||
deviceStateManager,
|
||||
sensorManager,
|
||||
handler,
|
||||
executor))
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun providesFoldStateLoggingProvider(
|
||||
optionalFoldStateProvider: Optional<FoldStateProvider>
|
||||
): Optional<FoldStateLoggingProvider> =
|
||||
optionalFoldStateProvider.map { foldStateProvider ->
|
||||
FoldStateLoggingProviderImpl(foldStateProvider, SystemClockImpl())
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideUnfoldTransitionConfig(context: Context): UnfoldTransitionConfig =
|
||||
@@ -77,13 +111,9 @@ class UnfoldTransitionModule {
|
||||
context: Context,
|
||||
windowManager: IWindowManager,
|
||||
unfoldTransitionProgressProvider: Optional<UnfoldTransitionProgressProvider>
|
||||
) =
|
||||
unfoldTransitionProgressProvider.map {
|
||||
provider -> NaturalRotationUnfoldProgressProvider(
|
||||
context,
|
||||
windowManager,
|
||||
provider
|
||||
)
|
||||
): Optional<NaturalRotationUnfoldProgressProvider> =
|
||||
unfoldTransitionProgressProvider.map { provider ->
|
||||
NaturalRotationUnfoldProgressProvider(context, windowManager, provider)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@@ -91,10 +121,8 @@ class UnfoldTransitionModule {
|
||||
@Singleton
|
||||
fun provideStatusBarScopedTransitionProvider(
|
||||
source: Optional<NaturalRotationUnfoldProgressProvider>
|
||||
) =
|
||||
source.map {
|
||||
provider -> ScopedUnfoldTransitionProgressProvider(provider)
|
||||
}
|
||||
): Optional<ScopedUnfoldTransitionProgressProvider> =
|
||||
source.map { provider -> ScopedUnfoldTransitionProgressProvider(provider) }
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
|
||||
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.unfold
|
||||
|
||||
import android.testing.AndroidTestingRunner
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.unfold.FoldStateLoggingProvider.FoldStateLoggingListener
|
||||
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_HALF_OPEN
|
||||
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.FoldStateProvider
|
||||
import com.android.systemui.unfold.updates.FoldStateProvider.FoldUpdate
|
||||
import com.android.systemui.util.time.FakeSystemClock
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.ArgumentCaptor
|
||||
import org.mockito.Captor
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.verify
|
||||
import org.mockito.MockitoAnnotations
|
||||
|
||||
@RunWith(AndroidTestingRunner::class)
|
||||
@SmallTest
|
||||
class FoldStateLoggingProviderTest : SysuiTestCase() {
|
||||
|
||||
@Captor
|
||||
private lateinit var foldUpdatesListener: ArgumentCaptor<FoldStateProvider.FoldUpdatesListener>
|
||||
|
||||
@Mock private lateinit var foldStateProvider: FoldStateProvider
|
||||
|
||||
private val fakeClock = FakeSystemClock()
|
||||
|
||||
private lateinit var foldStateLoggingProvider: FoldStateLoggingProvider
|
||||
|
||||
private val foldLoggingUpdates: MutableList<FoldStateChange> = arrayListOf()
|
||||
|
||||
private val foldStateLoggingListener =
|
||||
object : FoldStateLoggingListener {
|
||||
override fun onFoldUpdate(foldStateUpdate: FoldStateChange) {
|
||||
foldLoggingUpdates.add(foldStateUpdate)
|
||||
}
|
||||
}
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
|
||||
foldStateLoggingProvider =
|
||||
FoldStateLoggingProviderImpl(foldStateProvider, fakeClock).apply {
|
||||
addCallback(foldStateLoggingListener)
|
||||
init()
|
||||
}
|
||||
|
||||
verify(foldStateProvider).addCallback(foldUpdatesListener.capture())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onFoldUpdate_noPreviousOne_finishHalfOpen_nothingReported() {
|
||||
sendFoldUpdate(FOLD_UPDATE_FINISH_HALF_OPEN)
|
||||
|
||||
assertThat(foldLoggingUpdates).isEmpty()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onFoldUpdate_noPreviousOne_finishFullOpen_nothingReported() {
|
||||
sendFoldUpdate(FOLD_UPDATE_FINISH_FULL_OPEN)
|
||||
|
||||
assertThat(foldLoggingUpdates).isEmpty()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onFoldUpdate_noPreviousOne_finishClosed_nothingReported() {
|
||||
sendFoldUpdate(FOLD_UPDATE_FINISH_CLOSED)
|
||||
|
||||
assertThat(foldLoggingUpdates).isEmpty()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onFoldUpdate_startOpening_fullOpen_changeReported() {
|
||||
val dtTime = 10L
|
||||
|
||||
sendFoldUpdate(FOLD_UPDATE_START_OPENING)
|
||||
fakeClock.advanceTime(dtTime)
|
||||
sendFoldUpdate(FOLD_UPDATE_FINISH_FULL_OPEN)
|
||||
|
||||
assertThat(foldLoggingUpdates)
|
||||
.containsExactly(FoldStateChange(FULLY_CLOSED, FULLY_OPENED, dtTime))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onFoldUpdate_startClosingThenFinishClosed_noInitialState_nothingReported() {
|
||||
val dtTime = 10L
|
||||
|
||||
sendFoldUpdate(FOLD_UPDATE_START_CLOSING)
|
||||
fakeClock.advanceTime(dtTime)
|
||||
sendFoldUpdate(FOLD_UPDATE_FINISH_CLOSED)
|
||||
|
||||
assertThat(foldLoggingUpdates).isEmpty()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onFoldUpdate_startClosingThenFinishClosed_initiallyOpened_changeReported() {
|
||||
val dtTime = 10L
|
||||
sendFoldUpdate(FOLD_UPDATE_FINISH_FULL_OPEN)
|
||||
|
||||
sendFoldUpdate(FOLD_UPDATE_START_CLOSING)
|
||||
fakeClock.advanceTime(dtTime)
|
||||
sendFoldUpdate(FOLD_UPDATE_FINISH_CLOSED)
|
||||
|
||||
assertThat(foldLoggingUpdates)
|
||||
.containsExactly(FoldStateChange(FULLY_OPENED, FULLY_CLOSED, dtTime))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onFoldUpdate_startOpeningThenHalf_initiallyClosed_changeReported() {
|
||||
val dtTime = 10L
|
||||
sendFoldUpdate(FOLD_UPDATE_FINISH_CLOSED)
|
||||
|
||||
sendFoldUpdate(FOLD_UPDATE_START_OPENING)
|
||||
fakeClock.advanceTime(dtTime)
|
||||
sendFoldUpdate(FOLD_UPDATE_FINISH_HALF_OPEN)
|
||||
|
||||
assertThat(foldLoggingUpdates)
|
||||
.containsExactly(FoldStateChange(FULLY_CLOSED, HALF_OPENED, dtTime))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onFoldUpdate_startClosingThenHalf_initiallyOpened_changeReported() {
|
||||
val dtTime = 10L
|
||||
sendFoldUpdate(FOLD_UPDATE_FINISH_FULL_OPEN)
|
||||
|
||||
sendFoldUpdate(FOLD_UPDATE_START_CLOSING)
|
||||
fakeClock.advanceTime(dtTime)
|
||||
sendFoldUpdate(FOLD_UPDATE_FINISH_HALF_OPEN)
|
||||
|
||||
assertThat(foldLoggingUpdates)
|
||||
.containsExactly(FoldStateChange(FULLY_OPENED, HALF_OPENED, dtTime))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onFoldUpdate_foldThenUnfold_multipleReported() {
|
||||
val foldTime = 24L
|
||||
val unfoldTime = 42L
|
||||
val waitingTime = 424L
|
||||
sendFoldUpdate(FOLD_UPDATE_FINISH_FULL_OPEN)
|
||||
|
||||
// Fold
|
||||
sendFoldUpdate(FOLD_UPDATE_START_CLOSING)
|
||||
fakeClock.advanceTime(foldTime)
|
||||
sendFoldUpdate(FOLD_UPDATE_FINISH_CLOSED)
|
||||
fakeClock.advanceTime(waitingTime)
|
||||
// unfold
|
||||
sendFoldUpdate(FOLD_UPDATE_START_OPENING)
|
||||
fakeClock.advanceTime(unfoldTime)
|
||||
sendFoldUpdate(FOLD_UPDATE_FINISH_FULL_OPEN)
|
||||
|
||||
assertThat(foldLoggingUpdates)
|
||||
.containsExactly(
|
||||
FoldStateChange(FULLY_OPENED, FULLY_CLOSED, foldTime),
|
||||
FoldStateChange(FULLY_CLOSED, FULLY_OPENED, unfoldTime))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun uninit_removesCallback() {
|
||||
foldStateLoggingProvider.uninit()
|
||||
|
||||
verify(foldStateProvider).removeCallback(foldUpdatesListener.value)
|
||||
}
|
||||
|
||||
private fun sendFoldUpdate(@FoldUpdate foldUpdate: Int) {
|
||||
foldUpdatesListener.value.onFoldUpdate(foldUpdate)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user