1 /* 2 * Copyright (C) 2017 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 package com.android.systemui.shade 17 18 import android.os.SystemClock 19 import android.testing.AndroidTestingRunner 20 import android.testing.TestableLooper.RunWithLooper 21 import android.view.MotionEvent 22 import android.widget.FrameLayout 23 import androidx.test.filters.SmallTest 24 import com.android.keyguard.KeyguardMessageAreaController 25 import com.android.keyguard.KeyguardSecurityContainerController 26 import com.android.keyguard.LockIconViewController 27 import com.android.keyguard.dagger.KeyguardBouncerComponent 28 import com.android.systemui.R 29 import com.android.systemui.SysuiTestCase 30 import com.android.systemui.back.domain.interactor.BackActionInteractor 31 import com.android.systemui.bouncer.data.factory.BouncerMessageFactory 32 import com.android.systemui.bouncer.data.repository.FakeBouncerMessageRepository 33 import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor 34 import com.android.systemui.bouncer.domain.interactor.CountDownTimerUtil 35 import com.android.systemui.bouncer.ui.viewmodel.KeyguardBouncerViewModel 36 import com.android.systemui.classifier.FalsingCollectorFake 37 import com.android.systemui.dock.DockManager 38 import com.android.systemui.dump.logcatLogBuffer 39 import com.android.systemui.flags.FakeFeatureFlags 40 import com.android.systemui.flags.Flags 41 import com.android.systemui.keyevent.domain.interactor.KeyEventInteractor 42 import com.android.systemui.keyguard.KeyguardUnlockAnimationController 43 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor 44 import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel 45 import com.android.systemui.log.BouncerLogger 46 import com.android.systemui.power.domain.interactor.PowerInteractor 47 import com.android.systemui.shade.NotificationShadeWindowView.InteractionEventHandler 48 import com.android.systemui.statusbar.DragDownHelper 49 import com.android.systemui.statusbar.LockscreenShadeTransitionController 50 import com.android.systemui.statusbar.NotificationInsetsController 51 import com.android.systemui.statusbar.NotificationShadeDepthController 52 import com.android.systemui.statusbar.NotificationShadeWindowController 53 import com.android.systemui.statusbar.SysuiStatusBarStateController 54 import com.android.systemui.statusbar.notification.data.repository.NotificationExpansionRepository 55 import com.android.systemui.statusbar.notification.stack.AmbientState 56 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout 57 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController 58 import com.android.systemui.statusbar.phone.CentralSurfaces 59 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager 60 import com.android.systemui.statusbar.window.StatusBarWindowStateController 61 import com.android.systemui.unfold.UnfoldTransitionProgressProvider 62 import com.android.systemui.user.data.repository.FakeUserRepository 63 import com.android.systemui.util.mockito.any 64 import com.android.systemui.util.mockito.mock 65 import com.android.systemui.util.mockito.whenever 66 import com.android.systemui.util.time.FakeSystemClock 67 import com.google.common.truth.Truth.assertThat 68 import java.util.Optional 69 import kotlinx.coroutines.flow.emptyFlow 70 import kotlinx.coroutines.test.TestScope 71 import kotlinx.coroutines.test.runTest 72 import org.junit.Before 73 import org.junit.Test 74 import org.junit.runner.RunWith 75 import org.mockito.ArgumentCaptor 76 import org.mockito.Captor 77 import org.mockito.Mock 78 import org.mockito.Mockito 79 import org.mockito.Mockito.spy 80 import org.mockito.Mockito.verify 81 import org.mockito.MockitoAnnotations 82 83 @RunWith(AndroidTestingRunner::class) 84 @RunWithLooper(setAsMainLooper = true) 85 @SmallTest 86 class NotificationShadeWindowViewTest : SysuiTestCase() { 87 88 @Mock private lateinit var dragDownHelper: DragDownHelper 89 @Mock private lateinit var statusBarStateController: SysuiStatusBarStateController 90 @Mock private lateinit var shadeController: ShadeController 91 @Mock private lateinit var centralSurfaces: CentralSurfaces 92 @Mock private lateinit var backActionInteractor: BackActionInteractor 93 @Mock private lateinit var powerInteractor: PowerInteractor 94 @Mock private lateinit var dockManager: DockManager 95 @Mock private lateinit var notificationPanelViewController: NotificationPanelViewController 96 @Mock private lateinit var notificationStackScrollLayout: NotificationStackScrollLayout 97 @Mock private lateinit var notificationShadeDepthController: NotificationShadeDepthController 98 @Mock private lateinit var notificationShadeWindowController: NotificationShadeWindowController 99 @Mock 100 private lateinit var notificationStackScrollLayoutController: 101 NotificationStackScrollLayoutController 102 @Mock private lateinit var statusBarKeyguardViewManager: StatusBarKeyguardViewManager 103 @Mock private lateinit var statusBarWindowStateController: StatusBarWindowStateController 104 @Mock 105 private lateinit var lockscreenShadeTransitionController: LockscreenShadeTransitionController 106 @Mock private lateinit var lockIconViewController: LockIconViewController 107 @Mock private lateinit var keyguardUnlockAnimationController: KeyguardUnlockAnimationController 108 @Mock private lateinit var ambientState: AmbientState 109 @Mock private lateinit var shadeLogger: ShadeLogger 110 @Mock private lateinit var pulsingGestureListener: PulsingGestureListener 111 @Mock 112 private lateinit var mLockscreenHostedDreamGestureListener: LockscreenHostedDreamGestureListener 113 @Mock private lateinit var keyguardBouncerViewModel: KeyguardBouncerViewModel 114 @Mock private lateinit var keyguardBouncerComponentFactory: KeyguardBouncerComponent.Factory 115 @Mock private lateinit var keyguardBouncerComponent: KeyguardBouncerComponent 116 @Mock 117 private lateinit var keyguardSecurityContainerController: KeyguardSecurityContainerController 118 @Mock 119 private lateinit var unfoldTransitionProgressProvider: 120 Optional<UnfoldTransitionProgressProvider> 121 @Mock private lateinit var notificationInsetsController: NotificationInsetsController 122 @Mock private lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor 123 @Mock 124 private lateinit var primaryBouncerToGoneTransitionViewModel: 125 PrimaryBouncerToGoneTransitionViewModel 126 @Captor 127 private lateinit var interactionEventHandlerCaptor: ArgumentCaptor<InteractionEventHandler> 128 129 private lateinit var underTest: NotificationShadeWindowView 130 private lateinit var controller: NotificationShadeWindowViewController 131 private lateinit var interactionEventHandler: InteractionEventHandler 132 private lateinit var testScope: TestScope 133 134 @Before 135 fun setUp() { 136 MockitoAnnotations.initMocks(this) 137 underTest = spy(NotificationShadeWindowView(context, null)) 138 whenever( 139 underTest.findViewById<NotificationStackScrollLayout>( 140 R.id.notification_stack_scroller 141 ) 142 ) 143 .thenReturn(notificationStackScrollLayout) 144 whenever(underTest.findViewById<FrameLayout>(R.id.keyguard_bouncer_container)) 145 .thenReturn(mock()) 146 whenever(keyguardBouncerComponentFactory.create(any())).thenReturn(keyguardBouncerComponent) 147 whenever(keyguardBouncerComponent.securityContainerController) 148 .thenReturn(keyguardSecurityContainerController) 149 whenever(statusBarStateController.isDozing).thenReturn(false) 150 mDependency.injectTestDependency(ShadeController::class.java, shadeController) 151 whenever(dockManager.isDocked).thenReturn(false) 152 whenever(keyguardTransitionInteractor.lockscreenToDreamingTransition) 153 .thenReturn(emptyFlow()) 154 155 val featureFlags = FakeFeatureFlags() 156 featureFlags.set(Flags.TRACKPAD_GESTURE_COMMON, true) 157 featureFlags.set(Flags.TRACKPAD_GESTURE_FEATURES, false) 158 featureFlags.set(Flags.SPLIT_SHADE_SUBPIXEL_OPTIMIZATION, true) 159 featureFlags.set(Flags.REVAMPED_BOUNCER_MESSAGES, true) 160 featureFlags.set(Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED, false) 161 testScope = TestScope() 162 controller = 163 NotificationShadeWindowViewController( 164 lockscreenShadeTransitionController, 165 FalsingCollectorFake(), 166 statusBarStateController, 167 dockManager, 168 notificationShadeDepthController, 169 underTest, 170 notificationPanelViewController, 171 ShadeExpansionStateManager(), 172 notificationStackScrollLayoutController, 173 statusBarKeyguardViewManager, 174 statusBarWindowStateController, 175 lockIconViewController, 176 centralSurfaces, 177 backActionInteractor, 178 powerInteractor, 179 notificationShadeWindowController, 180 unfoldTransitionProgressProvider, 181 keyguardUnlockAnimationController, 182 notificationInsetsController, 183 ambientState, 184 shadeLogger, 185 pulsingGestureListener, 186 mLockscreenHostedDreamGestureListener, 187 keyguardBouncerViewModel, 188 keyguardBouncerComponentFactory, 189 Mockito.mock(KeyguardMessageAreaController.Factory::class.java), 190 keyguardTransitionInteractor, 191 primaryBouncerToGoneTransitionViewModel, 192 NotificationExpansionRepository(), 193 featureFlags, 194 FakeSystemClock(), 195 BouncerMessageInteractor( 196 FakeBouncerMessageRepository(), 197 Mockito.mock(BouncerMessageFactory::class.java), 198 FakeUserRepository(), 199 CountDownTimerUtil(), 200 featureFlags 201 ), 202 BouncerLogger(logcatLogBuffer("BouncerLog")), 203 Mockito.mock(KeyEventInteractor::class.java), 204 ) 205 206 controller.setupExpandedStatusBar() 207 controller.setDragDownHelper(dragDownHelper) 208 } 209 210 @Test 211 fun testDragDownHelperCalledWhenDraggingDown() = 212 testScope.runTest { 213 whenever(dragDownHelper.isDraggingDown).thenReturn(true) 214 val now = SystemClock.elapsedRealtime() 215 val ev = MotionEvent.obtain(now, now, MotionEvent.ACTION_UP, 0f, 0f, 0 /* meta */) 216 underTest.onTouchEvent(ev) 217 verify(dragDownHelper).onTouchEvent(ev) 218 ev.recycle() 219 } 220 221 @Test 222 fun testInterceptTouchWhenShowingAltAuth() = 223 testScope.runTest { 224 captureInteractionEventHandler() 225 226 // WHEN showing alt auth, not dozing, drag down helper doesn't want to intercept 227 whenever(statusBarStateController.isDozing).thenReturn(false) 228 whenever(statusBarKeyguardViewManager.shouldInterceptTouchEvent(any())).thenReturn(true) 229 whenever(dragDownHelper.onInterceptTouchEvent(any())).thenReturn(false) 230 231 // THEN we should intercept touch 232 assertThat(interactionEventHandler.shouldInterceptTouchEvent(mock())).isTrue() 233 } 234 235 @Test 236 fun testNoInterceptTouch() = 237 testScope.runTest { 238 captureInteractionEventHandler() 239 240 // WHEN not showing alt auth, not dozing, drag down helper doesn't want to intercept 241 whenever(statusBarStateController.isDozing).thenReturn(false) 242 whenever(statusBarKeyguardViewManager.shouldInterceptTouchEvent(any())) 243 .thenReturn(false) 244 whenever(dragDownHelper.onInterceptTouchEvent(any())).thenReturn(false) 245 246 // THEN we shouldn't intercept touch 247 assertThat(interactionEventHandler.shouldInterceptTouchEvent(mock())).isFalse() 248 } 249 250 @Test 251 fun testHandleTouchEventWhenShowingAltAuth() = 252 testScope.runTest { 253 captureInteractionEventHandler() 254 255 // WHEN showing alt auth, not dozing, drag down helper doesn't want to intercept 256 whenever(statusBarStateController.isDozing).thenReturn(false) 257 whenever(statusBarKeyguardViewManager.onTouch(any())).thenReturn(true) 258 whenever(dragDownHelper.onInterceptTouchEvent(any())).thenReturn(false) 259 260 // THEN we should handle the touch 261 assertThat(interactionEventHandler.handleTouchEvent(mock())).isTrue() 262 } 263 264 private fun captureInteractionEventHandler() { 265 verify(underTest).setInteractionEventHandler(interactionEventHandlerCaptor.capture()) 266 interactionEventHandler = interactionEventHandlerCaptor.value 267 } 268 } 269