/* * Copyright (C) 2017 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.shade import android.os.SystemClock import android.testing.AndroidTestingRunner import android.testing.TestableLooper.RunWithLooper import android.view.MotionEvent import android.widget.FrameLayout import androidx.test.filters.SmallTest import com.android.keyguard.KeyguardMessageAreaController import com.android.keyguard.KeyguardSecurityContainerController import com.android.keyguard.LockIconViewController import com.android.keyguard.dagger.KeyguardBouncerComponent import com.android.systemui.R import com.android.systemui.SysuiTestCase import com.android.systemui.back.domain.interactor.BackActionInteractor import com.android.systemui.bouncer.data.factory.BouncerMessageFactory import com.android.systemui.bouncer.data.repository.FakeBouncerMessageRepository import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor import com.android.systemui.bouncer.domain.interactor.CountDownTimerUtil import com.android.systemui.bouncer.ui.viewmodel.KeyguardBouncerViewModel import com.android.systemui.classifier.FalsingCollectorFake import com.android.systemui.dock.DockManager import com.android.systemui.dump.logcatLogBuffer import com.android.systemui.flags.FakeFeatureFlags import com.android.systemui.flags.Flags import com.android.systemui.keyevent.domain.interactor.KeyEventInteractor import com.android.systemui.keyguard.KeyguardUnlockAnimationController import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel import com.android.systemui.log.BouncerLogger import com.android.systemui.power.domain.interactor.PowerInteractor import com.android.systemui.shade.NotificationShadeWindowView.InteractionEventHandler import com.android.systemui.statusbar.DragDownHelper import com.android.systemui.statusbar.LockscreenShadeTransitionController import com.android.systemui.statusbar.NotificationInsetsController import com.android.systemui.statusbar.NotificationShadeDepthController import com.android.systemui.statusbar.NotificationShadeWindowController import com.android.systemui.statusbar.SysuiStatusBarStateController import com.android.systemui.statusbar.notification.data.repository.NotificationExpansionRepository import com.android.systemui.statusbar.notification.stack.AmbientState import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController import com.android.systemui.statusbar.phone.CentralSurfaces import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager import com.android.systemui.statusbar.window.StatusBarWindowStateController import com.android.systemui.unfold.UnfoldTransitionProgressProvider import com.android.systemui.user.data.repository.FakeUserRepository import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever import com.android.systemui.util.time.FakeSystemClock import com.google.common.truth.Truth.assertThat import java.util.Optional import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runTest 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 import org.mockito.Mockito.spy import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations @RunWith(AndroidTestingRunner::class) @RunWithLooper(setAsMainLooper = true) @SmallTest class NotificationShadeWindowViewTest : SysuiTestCase() { @Mock private lateinit var dragDownHelper: DragDownHelper @Mock private lateinit var statusBarStateController: SysuiStatusBarStateController @Mock private lateinit var shadeController: ShadeController @Mock private lateinit var centralSurfaces: CentralSurfaces @Mock private lateinit var backActionInteractor: BackActionInteractor @Mock private lateinit var powerInteractor: PowerInteractor @Mock private lateinit var dockManager: DockManager @Mock private lateinit var notificationPanelViewController: NotificationPanelViewController @Mock private lateinit var notificationStackScrollLayout: NotificationStackScrollLayout @Mock private lateinit var notificationShadeDepthController: NotificationShadeDepthController @Mock private lateinit var notificationShadeWindowController: NotificationShadeWindowController @Mock private lateinit var notificationStackScrollLayoutController: NotificationStackScrollLayoutController @Mock private lateinit var statusBarKeyguardViewManager: StatusBarKeyguardViewManager @Mock private lateinit var statusBarWindowStateController: StatusBarWindowStateController @Mock private lateinit var lockscreenShadeTransitionController: LockscreenShadeTransitionController @Mock private lateinit var lockIconViewController: LockIconViewController @Mock private lateinit var keyguardUnlockAnimationController: KeyguardUnlockAnimationController @Mock private lateinit var ambientState: AmbientState @Mock private lateinit var shadeLogger: ShadeLogger @Mock private lateinit var pulsingGestureListener: PulsingGestureListener @Mock private lateinit var mLockscreenHostedDreamGestureListener: LockscreenHostedDreamGestureListener @Mock private lateinit var keyguardBouncerViewModel: KeyguardBouncerViewModel @Mock private lateinit var keyguardBouncerComponentFactory: KeyguardBouncerComponent.Factory @Mock private lateinit var keyguardBouncerComponent: KeyguardBouncerComponent @Mock private lateinit var keyguardSecurityContainerController: KeyguardSecurityContainerController @Mock private lateinit var unfoldTransitionProgressProvider: Optional @Mock private lateinit var notificationInsetsController: NotificationInsetsController @Mock private lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor @Mock private lateinit var primaryBouncerToGoneTransitionViewModel: PrimaryBouncerToGoneTransitionViewModel @Captor private lateinit var interactionEventHandlerCaptor: ArgumentCaptor private lateinit var underTest: NotificationShadeWindowView private lateinit var controller: NotificationShadeWindowViewController private lateinit var interactionEventHandler: InteractionEventHandler private lateinit var testScope: TestScope @Before fun setUp() { MockitoAnnotations.initMocks(this) underTest = spy(NotificationShadeWindowView(context, null)) whenever( underTest.findViewById( R.id.notification_stack_scroller ) ) .thenReturn(notificationStackScrollLayout) whenever(underTest.findViewById(R.id.keyguard_bouncer_container)) .thenReturn(mock()) whenever(keyguardBouncerComponentFactory.create(any())).thenReturn(keyguardBouncerComponent) whenever(keyguardBouncerComponent.securityContainerController) .thenReturn(keyguardSecurityContainerController) whenever(statusBarStateController.isDozing).thenReturn(false) mDependency.injectTestDependency(ShadeController::class.java, shadeController) whenever(dockManager.isDocked).thenReturn(false) whenever(keyguardTransitionInteractor.lockscreenToDreamingTransition) .thenReturn(emptyFlow()) val featureFlags = FakeFeatureFlags() featureFlags.set(Flags.TRACKPAD_GESTURE_COMMON, true) featureFlags.set(Flags.TRACKPAD_GESTURE_FEATURES, false) featureFlags.set(Flags.SPLIT_SHADE_SUBPIXEL_OPTIMIZATION, true) featureFlags.set(Flags.REVAMPED_BOUNCER_MESSAGES, true) featureFlags.set(Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED, false) testScope = TestScope() controller = NotificationShadeWindowViewController( lockscreenShadeTransitionController, FalsingCollectorFake(), statusBarStateController, dockManager, notificationShadeDepthController, underTest, notificationPanelViewController, ShadeExpansionStateManager(), notificationStackScrollLayoutController, statusBarKeyguardViewManager, statusBarWindowStateController, lockIconViewController, centralSurfaces, backActionInteractor, powerInteractor, notificationShadeWindowController, unfoldTransitionProgressProvider, keyguardUnlockAnimationController, notificationInsetsController, ambientState, shadeLogger, pulsingGestureListener, mLockscreenHostedDreamGestureListener, keyguardBouncerViewModel, keyguardBouncerComponentFactory, Mockito.mock(KeyguardMessageAreaController.Factory::class.java), keyguardTransitionInteractor, primaryBouncerToGoneTransitionViewModel, NotificationExpansionRepository(), featureFlags, FakeSystemClock(), BouncerMessageInteractor( FakeBouncerMessageRepository(), Mockito.mock(BouncerMessageFactory::class.java), FakeUserRepository(), CountDownTimerUtil(), featureFlags ), BouncerLogger(logcatLogBuffer("BouncerLog")), Mockito.mock(KeyEventInteractor::class.java), ) controller.setupExpandedStatusBar() controller.setDragDownHelper(dragDownHelper) } @Test fun testDragDownHelperCalledWhenDraggingDown() = testScope.runTest { whenever(dragDownHelper.isDraggingDown).thenReturn(true) val now = SystemClock.elapsedRealtime() val ev = MotionEvent.obtain(now, now, MotionEvent.ACTION_UP, 0f, 0f, 0 /* meta */) underTest.onTouchEvent(ev) verify(dragDownHelper).onTouchEvent(ev) ev.recycle() } @Test fun testInterceptTouchWhenShowingAltAuth() = testScope.runTest { captureInteractionEventHandler() // WHEN showing alt auth, not dozing, drag down helper doesn't want to intercept whenever(statusBarStateController.isDozing).thenReturn(false) whenever(statusBarKeyguardViewManager.shouldInterceptTouchEvent(any())).thenReturn(true) whenever(dragDownHelper.onInterceptTouchEvent(any())).thenReturn(false) // THEN we should intercept touch assertThat(interactionEventHandler.shouldInterceptTouchEvent(mock())).isTrue() } @Test fun testNoInterceptTouch() = testScope.runTest { captureInteractionEventHandler() // WHEN not showing alt auth, not dozing, drag down helper doesn't want to intercept whenever(statusBarStateController.isDozing).thenReturn(false) whenever(statusBarKeyguardViewManager.shouldInterceptTouchEvent(any())) .thenReturn(false) whenever(dragDownHelper.onInterceptTouchEvent(any())).thenReturn(false) // THEN we shouldn't intercept touch assertThat(interactionEventHandler.shouldInterceptTouchEvent(mock())).isFalse() } @Test fun testHandleTouchEventWhenShowingAltAuth() = testScope.runTest { captureInteractionEventHandler() // WHEN showing alt auth, not dozing, drag down helper doesn't want to intercept whenever(statusBarStateController.isDozing).thenReturn(false) whenever(statusBarKeyguardViewManager.onTouch(any())).thenReturn(true) whenever(dragDownHelper.onInterceptTouchEvent(any())).thenReturn(false) // THEN we should handle the touch assertThat(interactionEventHandler.handleTouchEvent(mock())).isTrue() } private fun captureInteractionEventHandler() { verify(underTest).setInteractionEventHandler(interactionEventHandlerCaptor.capture()) interactionEventHandler = interactionEventHandlerCaptor.value } }