/* * Copyright (C) 2021 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.hardware.devicestate.DeviceStateManager import android.hardware.devicestate.DeviceStateManager.FoldStateListener import android.provider.Settings import android.testing.AndroidTestingRunner import androidx.test.filters.SmallTest import com.android.internal.util.LatencyTracker import com.android.systemui.SysuiTestCase import com.android.systemui.keyguard.ScreenLifecycle import com.android.systemui.unfold.util.FoldableDeviceStates import com.android.systemui.unfold.util.FoldableTestUtils import com.android.systemui.util.mockito.any 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.never import org.mockito.Mockito.verify import org.mockito.Mockito.verifyNoMoreInteractions import org.mockito.MockitoAnnotations import java.util.Optional @RunWith(AndroidTestingRunner::class) @SmallTest class UnfoldLatencyTrackerTest : SysuiTestCase() { @Mock lateinit var latencyTracker: LatencyTracker @Mock lateinit var deviceStateManager: DeviceStateManager @Mock lateinit var screenLifecycle: ScreenLifecycle @Captor private lateinit var foldStateListenerCaptor: ArgumentCaptor @Captor private lateinit var screenLifecycleCaptor: ArgumentCaptor private lateinit var deviceStates: FoldableDeviceStates private lateinit var unfoldLatencyTracker: UnfoldLatencyTracker private val transitionProgressProvider = TestUnfoldTransitionProvider() @Before fun setUp() { MockitoAnnotations.initMocks(this) unfoldLatencyTracker = UnfoldLatencyTracker( latencyTracker, deviceStateManager, Optional.of(transitionProgressProvider), context.mainExecutor, context, context.contentResolver, screenLifecycle ).apply { init() } deviceStates = FoldableTestUtils.findDeviceStates(context) verify(deviceStateManager).registerCallback(any(), foldStateListenerCaptor.capture()) verify(screenLifecycle).addObserver(screenLifecycleCaptor.capture()) } @Test fun unfold_startedFolded_animationsDisabled_eventPropagatedOnScreenTurnedOnEvent() { setAnimationsEnabled(false) sendFoldEvent(folded = true) sendFoldEvent(folded = false) sendScreenTurnedOnEvent() verify(latencyTracker).onActionStart(any()) verify(latencyTracker).onActionEnd(any()) } @Test fun unfold_startedFolded_animationsEnabledOnScreenTurnedOn_eventNotFinished() { setAnimationsEnabled(true) sendFoldEvent(folded = true) sendFoldEvent(folded = false) sendScreenTurnedOnEvent() verify(latencyTracker).onActionStart(any()) verify(latencyTracker, never()).onActionEnd(any()) } @Test fun unfold_firstFoldEventAnimationsEnabledOnScreenTurnedOnAndTransitionStarted_eventNotPropagated() { setAnimationsEnabled(true) sendFoldEvent(folded = false) sendScreenTurnedOnEvent() transitionProgressProvider.onTransitionStarted() verifyNoMoreInteractions(latencyTracker) } @Test fun unfold_secondFoldEventAnimationsEnabledOnScreenTurnedOnAndTransitionStarted_eventPropagated() { setAnimationsEnabled(true) sendFoldEvent(folded = true) sendFoldEvent(folded = false) sendScreenTurnedOnEvent() transitionProgressProvider.onTransitionStarted() verify(latencyTracker).onActionStart(any()) verify(latencyTracker).onActionEnd(any()) } @Test fun unfold_unfoldFoldUnfoldAnimationsEnabledOnScreenTurnedOnAndTransitionStarted_eventPropagated() { setAnimationsEnabled(true) sendFoldEvent(folded = false) sendFoldEvent(folded = true) sendFoldEvent(folded = false) sendScreenTurnedOnEvent() transitionProgressProvider.onTransitionStarted() verify(latencyTracker).onActionStart(any()) verify(latencyTracker).onActionEnd(any()) } @Test fun fold_animationsDisabled_screenTurnedOn_eventNotPropagated() { setAnimationsEnabled(false) sendFoldEvent(folded = true) sendScreenTurnedOnEvent() // outer display on. verifyNoMoreInteractions(latencyTracker) } @Test fun fold_animationsEnabled_screenTurnedOn_eventNotPropagated() { setAnimationsEnabled(true) sendFoldEvent(folded = true) sendScreenTurnedOnEvent() // outer display on. transitionProgressProvider.onTransitionStarted() verifyNoMoreInteractions(latencyTracker) } @Test fun onScreenTurnedOn_stateNeverSet_eventNotPropagated() { sendScreenTurnedOnEvent() verifyNoMoreInteractions(latencyTracker) } private fun sendFoldEvent(folded: Boolean) { val state = if (folded) deviceStates.folded else deviceStates.unfolded foldStateListenerCaptor.value.onStateChanged(state) } private fun sendScreenTurnedOnEvent() { screenLifecycleCaptor.value.onScreenTurnedOn() } private fun setAnimationsEnabled(enabled: Boolean) { val durationScale = if (enabled) { 1f } else { 0f } // It uses [TestableSettingsProvider] and it will be cleared after the test Settings.Global.putString( context.contentResolver, Settings.Global.ANIMATOR_DURATION_SCALE, durationScale.toString() ) } }