1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.unfold 18 19 import android.hardware.devicestate.DeviceStateManager 20 import android.hardware.devicestate.DeviceStateManager.FoldStateListener 21 import android.provider.Settings 22 import android.testing.AndroidTestingRunner 23 import androidx.test.filters.SmallTest 24 import com.android.internal.util.LatencyTracker 25 import com.android.systemui.SysuiTestCase 26 import com.android.systemui.keyguard.ScreenLifecycle 27 import com.android.systemui.unfold.util.FoldableDeviceStates 28 import com.android.systemui.unfold.util.FoldableTestUtils 29 import com.android.systemui.util.mockito.any 30 import org.junit.Before 31 import org.junit.Test 32 import org.junit.runner.RunWith 33 import org.mockito.ArgumentCaptor 34 import org.mockito.Captor 35 import org.mockito.Mock 36 import org.mockito.Mockito.never 37 import org.mockito.Mockito.verify 38 import org.mockito.Mockito.verifyNoMoreInteractions 39 import org.mockito.MockitoAnnotations 40 import java.util.Optional 41 42 @RunWith(AndroidTestingRunner::class) 43 @SmallTest 44 class UnfoldLatencyTrackerTest : SysuiTestCase() { 45 46 @Mock 47 lateinit var latencyTracker: LatencyTracker 48 49 @Mock 50 lateinit var deviceStateManager: DeviceStateManager 51 52 @Mock 53 lateinit var screenLifecycle: ScreenLifecycle 54 55 @Captor 56 private lateinit var foldStateListenerCaptor: ArgumentCaptor<FoldStateListener> 57 58 @Captor 59 private lateinit var screenLifecycleCaptor: ArgumentCaptor<ScreenLifecycle.Observer> 60 61 private lateinit var deviceStates: FoldableDeviceStates 62 63 private lateinit var unfoldLatencyTracker: UnfoldLatencyTracker 64 65 private val transitionProgressProvider = TestUnfoldTransitionProvider() 66 67 @Before 68 fun setUp() { 69 MockitoAnnotations.initMocks(this) 70 unfoldLatencyTracker = UnfoldLatencyTracker( 71 latencyTracker, 72 deviceStateManager, 73 Optional.of(transitionProgressProvider), 74 context.mainExecutor, 75 context, 76 context.contentResolver, 77 screenLifecycle 78 ).apply { init() } 79 deviceStates = FoldableTestUtils.findDeviceStates(context) 80 81 verify(deviceStateManager).registerCallback(any(), foldStateListenerCaptor.capture()) 82 verify(screenLifecycle).addObserver(screenLifecycleCaptor.capture()) 83 } 84 85 @Test 86 fun unfold_startedFolded_animationsDisabled_eventPropagatedOnScreenTurnedOnEvent() { 87 setAnimationsEnabled(false) 88 sendFoldEvent(folded = true) 89 sendFoldEvent(folded = false) 90 91 sendScreenTurnedOnEvent() 92 93 verify(latencyTracker).onActionStart(any()) 94 verify(latencyTracker).onActionEnd(any()) 95 } 96 97 @Test 98 fun unfold_startedFolded_animationsEnabledOnScreenTurnedOn_eventNotFinished() { 99 setAnimationsEnabled(true) 100 sendFoldEvent(folded = true) 101 sendFoldEvent(folded = false) 102 103 sendScreenTurnedOnEvent() 104 105 verify(latencyTracker).onActionStart(any()) 106 verify(latencyTracker, never()).onActionEnd(any()) 107 } 108 109 @Test 110 fun unfold_firstFoldEventAnimationsEnabledOnScreenTurnedOnAndTransitionStarted_eventNotPropagated() { 111 setAnimationsEnabled(true) 112 sendFoldEvent(folded = false) 113 114 sendScreenTurnedOnEvent() 115 transitionProgressProvider.onTransitionStarted() 116 117 verifyNoMoreInteractions(latencyTracker) 118 } 119 120 @Test 121 fun unfold_secondFoldEventAnimationsEnabledOnScreenTurnedOnAndTransitionStarted_eventPropagated() { 122 setAnimationsEnabled(true) 123 sendFoldEvent(folded = true) 124 sendFoldEvent(folded = false) 125 126 sendScreenTurnedOnEvent() 127 transitionProgressProvider.onTransitionStarted() 128 129 verify(latencyTracker).onActionStart(any()) 130 verify(latencyTracker).onActionEnd(any()) 131 } 132 133 @Test 134 fun unfold_unfoldFoldUnfoldAnimationsEnabledOnScreenTurnedOnAndTransitionStarted_eventPropagated() { 135 setAnimationsEnabled(true) 136 sendFoldEvent(folded = false) 137 sendFoldEvent(folded = true) 138 sendFoldEvent(folded = false) 139 140 sendScreenTurnedOnEvent() 141 transitionProgressProvider.onTransitionStarted() 142 143 verify(latencyTracker).onActionStart(any()) 144 verify(latencyTracker).onActionEnd(any()) 145 } 146 147 @Test 148 fun fold_animationsDisabled_screenTurnedOn_eventNotPropagated() { 149 setAnimationsEnabled(false) 150 sendFoldEvent(folded = true) 151 152 sendScreenTurnedOnEvent() // outer display on. 153 154 verifyNoMoreInteractions(latencyTracker) 155 } 156 157 @Test 158 fun fold_animationsEnabled_screenTurnedOn_eventNotPropagated() { 159 setAnimationsEnabled(true) 160 sendFoldEvent(folded = true) 161 162 sendScreenTurnedOnEvent() // outer display on. 163 transitionProgressProvider.onTransitionStarted() 164 165 verifyNoMoreInteractions(latencyTracker) 166 } 167 168 @Test 169 fun onScreenTurnedOn_stateNeverSet_eventNotPropagated() { 170 sendScreenTurnedOnEvent() 171 172 verifyNoMoreInteractions(latencyTracker) 173 } 174 175 private fun sendFoldEvent(folded: Boolean) { 176 val state = if (folded) deviceStates.folded else deviceStates.unfolded 177 foldStateListenerCaptor.value.onStateChanged(state) 178 } 179 180 private fun sendScreenTurnedOnEvent() { 181 screenLifecycleCaptor.value.onScreenTurnedOn() 182 } 183 184 private fun setAnimationsEnabled(enabled: Boolean) { 185 val durationScale = 186 if (enabled) { 187 1f 188 } else { 189 0f 190 } 191 192 // It uses [TestableSettingsProvider] and it will be cleared after the test 193 Settings.Global.putString( 194 context.contentResolver, 195 Settings.Global.ANIMATOR_DURATION_SCALE, 196 durationScale.toString() 197 ) 198 } 199 }