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.shade 18 19 import android.testing.AndroidTestingRunner 20 import android.view.View 21 import android.view.ViewGroup 22 import androidx.test.filters.SmallTest 23 import com.android.systemui.R 24 import com.android.systemui.SysuiTestCase 25 import com.android.systemui.plugins.statusbar.StatusBarStateController 26 import com.android.systemui.statusbar.StatusBarState.KEYGUARD 27 import com.android.systemui.statusbar.StatusBarState.SHADE 28 import com.android.systemui.statusbar.StatusBarState.SHADE_LOCKED 29 import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener 30 import com.android.systemui.unfold.util.NaturalRotationUnfoldProgressProvider 31 import com.android.systemui.util.mockito.capture 32 import com.android.systemui.util.mockito.whenever 33 import com.google.common.truth.Truth.assertThat 34 import org.junit.Before 35 import org.junit.Test 36 import org.junit.runner.RunWith 37 import org.mockito.ArgumentCaptor 38 import org.mockito.Captor 39 import org.mockito.Mock 40 import org.mockito.Mockito.atLeastOnce 41 import org.mockito.Mockito.verify 42 import org.mockito.MockitoAnnotations 43 44 /** 45 * Translates items away/towards the hinge when the device is opened/closed. This is controlled by 46 * the set of ids, which also dictact which direction to move and when, via a filter fn. 47 */ 48 @SmallTest 49 @RunWith(AndroidTestingRunner::class) 50 class NotificationPanelUnfoldAnimationControllerTest : SysuiTestCase() { 51 52 @Mock private lateinit var progressProvider: NaturalRotationUnfoldProgressProvider 53 54 @Captor private lateinit var progressListenerCaptor: ArgumentCaptor<TransitionProgressListener> 55 56 @Mock private lateinit var parent: ViewGroup 57 58 @Mock private lateinit var splitShadeStatusBar: ViewGroup 59 60 @Mock private lateinit var statusBarStateController: StatusBarStateController 61 62 private lateinit var underTest: NotificationPanelUnfoldAnimationController 63 private lateinit var progressListeners: List<TransitionProgressListener> 64 private var xTranslationMax = 0f 65 66 @Before 67 fun setup() { 68 MockitoAnnotations.initMocks(this) 69 70 xTranslationMax = 71 context.resources.getDimensionPixelSize(R.dimen.notification_side_paddings).toFloat() 72 73 underTest = 74 NotificationPanelUnfoldAnimationController( 75 context, 76 statusBarStateController, 77 progressProvider 78 ) 79 whenever(parent.findViewById<ViewGroup>(R.id.split_shade_status_bar)).thenReturn( 80 splitShadeStatusBar 81 ) 82 underTest.setup(parent) 83 84 verify(progressProvider, atLeastOnce()).addCallback(capture(progressListenerCaptor)) 85 progressListeners = progressListenerCaptor.allValues 86 } 87 88 @Test 89 fun whenInKeyguardState_viewDoesNotMove() { 90 whenever(statusBarStateController.getState()).thenReturn(KEYGUARD) 91 92 val view = View(context) 93 whenever(parent.findViewById<View>(R.id.quick_settings_panel)).thenReturn(view) 94 95 onTransitionStarted() 96 assertThat(view.translationX).isZero() 97 98 onTransitionProgress(0f) 99 assertThat(view.translationX).isZero() 100 101 onTransitionProgress(0.5f) 102 assertThat(view.translationX).isZero() 103 104 onTransitionFinished() 105 assertThat(view.translationX).isZero() 106 } 107 108 @Test 109 fun whenInShadeState_viewDoesMove() { 110 whenever(statusBarStateController.getState()).thenReturn(SHADE) 111 112 val view = View(context) 113 whenever(parent.findViewById<View>(R.id.quick_settings_panel)).thenReturn(view) 114 115 onTransitionStarted() 116 assertThat(view.translationX).isZero() 117 118 onTransitionProgress(0f) 119 assertThat(view.translationX).isEqualTo(xTranslationMax) 120 121 onTransitionProgress(0.5f) 122 assertThat(view.translationX).isEqualTo(0.5f * xTranslationMax) 123 124 onTransitionFinished() 125 assertThat(view.translationX).isZero() 126 } 127 128 @Test 129 fun whenInShadeLockedState_viewDoesMove() { 130 whenever(statusBarStateController.getState()).thenReturn(SHADE_LOCKED) 131 132 val view = View(context) 133 whenever(parent.findViewById<View>(R.id.quick_settings_panel)).thenReturn(view) 134 135 onTransitionStarted() 136 assertThat(view.translationX).isZero() 137 138 onTransitionProgress(0f) 139 assertThat(view.translationX).isEqualTo(xTranslationMax) 140 141 onTransitionProgress(0.5f) 142 assertThat(view.translationX).isEqualTo(0.5f * xTranslationMax) 143 144 onTransitionFinished() 145 assertThat(view.translationX).isZero() 146 } 147 148 @Test 149 fun whenInKeyguardState_statusBarViewDoesNotMove() { 150 whenever(statusBarStateController.getState()).thenReturn(KEYGUARD) 151 152 val view = View(context) 153 whenever(splitShadeStatusBar.findViewById<View>(R.id.date)).thenReturn(view) 154 155 onTransitionStarted() 156 assertThat(view.translationX).isZero() 157 158 onTransitionProgress(0f) 159 assertThat(view.translationX).isZero() 160 161 onTransitionProgress(0.5f) 162 assertThat(view.translationX).isZero() 163 164 onTransitionFinished() 165 assertThat(view.translationX).isZero() 166 } 167 168 @Test 169 fun whenInShadeState_statusBarViewDoesMove() { 170 whenever(statusBarStateController.getState()).thenReturn(SHADE) 171 172 val view = View(context) 173 whenever(splitShadeStatusBar.findViewById<View>(R.id.date)).thenReturn(view) 174 175 onTransitionStarted() 176 assertThat(view.translationX).isZero() 177 178 onTransitionProgress(0f) 179 assertThat(view.translationX).isEqualTo(xTranslationMax) 180 181 onTransitionProgress(0.5f) 182 assertThat(view.translationX).isEqualTo(0.5f * xTranslationMax) 183 184 onTransitionFinished() 185 assertThat(view.translationX).isZero() 186 } 187 188 @Test 189 fun whenInShadeLockedState_statusBarViewDoesMove() { 190 whenever(statusBarStateController.getState()).thenReturn(SHADE_LOCKED) 191 192 val view = View(context) 193 whenever(splitShadeStatusBar.findViewById<View>(R.id.date)).thenReturn(view) 194 onTransitionStarted() 195 assertThat(view.translationX).isZero() 196 197 onTransitionProgress(0f) 198 assertThat(view.translationX).isEqualTo(xTranslationMax) 199 200 onTransitionProgress(0.5f) 201 assertThat(view.translationX).isEqualTo(0.5f * xTranslationMax) 202 203 onTransitionFinished() 204 assertThat(view.translationX).isZero() 205 } 206 207 private fun onTransitionStarted() { 208 progressListeners.forEach { it.onTransitionStarted() } 209 } 210 211 private fun onTransitionProgress(progress: Float) { 212 progressListeners.forEach { it.onTransitionProgress(progress) } 213 } 214 215 private fun onTransitionFinished() { 216 progressListeners.forEach { it.onTransitionFinished() } 217 } 218 219 } 220