| /* |
| * 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.statusbar.phone |
| |
| import android.testing.AndroidTestingRunner |
| import android.testing.TestableLooper.RunWithLooper |
| import android.view.MotionEvent |
| import androidx.test.filters.SmallTest |
| import com.android.keyguard.LockIconViewController |
| import com.android.systemui.SysuiTestCase |
| import com.android.systemui.classifier.FalsingCollectorFake |
| import com.android.systemui.dock.DockManager |
| import com.android.systemui.keyguard.KeyguardUnlockAnimationController |
| import com.android.systemui.lowlightclock.LowLightClockController |
| import com.android.systemui.statusbar.LockscreenShadeTransitionController |
| import com.android.systemui.statusbar.NotificationShadeDepthController |
| import com.android.systemui.statusbar.NotificationShadeWindowController |
| import com.android.systemui.statusbar.SysuiStatusBarStateController |
| import com.android.systemui.statusbar.notification.stack.AmbientState |
| import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController |
| import com.android.systemui.statusbar.phone.NotificationShadeWindowView.InteractionEventHandler |
| import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager |
| import com.android.systemui.statusbar.window.StatusBarWindowStateController |
| import com.android.systemui.tuner.TunerService |
| import com.google.common.truth.Truth.assertThat |
| import java.util.Optional |
| import org.junit.Before |
| import org.junit.Test |
| import org.junit.runner.RunWith |
| import org.mockito.ArgumentCaptor |
| import org.mockito.ArgumentMatchers |
| import org.mockito.Mock |
| import org.mockito.Mockito.anyFloat |
| import org.mockito.Mockito.never |
| import org.mockito.Mockito.verify |
| import org.mockito.Mockito.`when` as whenever |
| import org.mockito.MockitoAnnotations |
| |
| @RunWith(AndroidTestingRunner::class) |
| @RunWithLooper(setAsMainLooper = true) |
| @SmallTest |
| class NotificationShadeWindowViewControllerTest : SysuiTestCase() { |
| @Mock |
| private lateinit var view: NotificationShadeWindowView |
| @Mock |
| private lateinit var tunserService: TunerService |
| @Mock |
| private lateinit var sysuiStatusBarStateController: SysuiStatusBarStateController |
| @Mock |
| private lateinit var centralSurfaces: CentralSurfaces |
| @Mock |
| private lateinit var dockManager: DockManager |
| @Mock |
| private lateinit var notificationPanelViewController: NotificationPanelViewController |
| @Mock |
| private lateinit var notificationShadeDepthController: NotificationShadeDepthController |
| @Mock |
| private lateinit var notificationShadeWindowController: NotificationShadeWindowController |
| @Mock |
| private lateinit var keyguardUnlockAnimationController: KeyguardUnlockAnimationController |
| @Mock |
| private lateinit var ambientState: AmbientState |
| @Mock |
| private lateinit var stackScrollLayoutController: 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 phoneStatusBarViewController: PhoneStatusBarViewController |
| @Mock |
| private lateinit var lowLightClockController: LowLightClockController |
| |
| private lateinit var interactionEventHandlerCaptor: ArgumentCaptor<InteractionEventHandler> |
| private lateinit var interactionEventHandler: InteractionEventHandler |
| |
| private lateinit var underTest: NotificationShadeWindowViewController |
| |
| @Before |
| fun setUp() { |
| MockitoAnnotations.initMocks(this) |
| whenever(view.bottom).thenReturn(VIEW_BOTTOM) |
| |
| underTest = NotificationShadeWindowViewController( |
| lockscreenShadeTransitionController, |
| FalsingCollectorFake(), |
| tunserService, |
| sysuiStatusBarStateController, |
| dockManager, |
| notificationShadeDepthController, |
| view, |
| notificationPanelViewController, |
| PanelExpansionStateManager(), |
| stackScrollLayoutController, |
| statusBarKeyguardViewManager, |
| statusBarWindowStateController, |
| lockIconViewController, |
| Optional.of(lowLightClockController), |
| centralSurfaces, |
| notificationShadeWindowController, |
| keyguardUnlockAnimationController, |
| ambientState |
| ) |
| underTest.setupExpandedStatusBar() |
| |
| interactionEventHandlerCaptor = |
| ArgumentCaptor.forClass(InteractionEventHandler::class.java) |
| verify(view).setInteractionEventHandler(interactionEventHandlerCaptor.capture()) |
| interactionEventHandler = interactionEventHandlerCaptor.value |
| } |
| |
| // Note: So far, these tests only cover interactions with the status bar view controller. More |
| // tests need to be added to test the rest of handleDispatchTouchEvent. |
| |
| @Test |
| fun handleDispatchTouchEvent_nullStatusBarViewController_returnsFalse() { |
| underTest.setStatusBarViewController(null) |
| |
| val returnVal = interactionEventHandler.handleDispatchTouchEvent(downEv) |
| |
| assertThat(returnVal).isFalse() |
| } |
| |
| @Test |
| fun handleDispatchTouchEvent_downTouchBelowView_sendsTouchToSb() { |
| underTest.setStatusBarViewController(phoneStatusBarViewController) |
| val ev = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, VIEW_BOTTOM + 4f, 0) |
| whenever(phoneStatusBarViewController.sendTouchToView(ev)).thenReturn(true) |
| |
| val returnVal = interactionEventHandler.handleDispatchTouchEvent(ev) |
| |
| verify(phoneStatusBarViewController).sendTouchToView(ev) |
| assertThat(returnVal).isTrue() |
| } |
| |
| @Test |
| fun handleDispatchTouchEvent_downTouchBelowViewThenAnotherTouch_sendsTouchToSb() { |
| underTest.setStatusBarViewController(phoneStatusBarViewController) |
| val downEvBelow = MotionEvent.obtain( |
| 0L, 0L, MotionEvent.ACTION_DOWN, 0f, VIEW_BOTTOM + 4f, 0 |
| ) |
| interactionEventHandler.handleDispatchTouchEvent(downEvBelow) |
| |
| val nextEvent = MotionEvent.obtain( |
| 0L, 0L, MotionEvent.ACTION_MOVE, 0f, VIEW_BOTTOM + 5f, 0 |
| ) |
| whenever(phoneStatusBarViewController.sendTouchToView(nextEvent)).thenReturn(true) |
| |
| val returnVal = interactionEventHandler.handleDispatchTouchEvent(nextEvent) |
| |
| verify(phoneStatusBarViewController).sendTouchToView(nextEvent) |
| assertThat(returnVal).isTrue() |
| } |
| |
| @Test |
| fun handleDispatchTouchEvent_downAndPanelCollapsedAndInSbBoundAndSbWindowShow_sendsTouchToSb() { |
| underTest.setStatusBarViewController(phoneStatusBarViewController) |
| whenever(statusBarWindowStateController.windowIsShowing()).thenReturn(true) |
| whenever(notificationPanelViewController.isFullyCollapsed).thenReturn(true) |
| whenever(phoneStatusBarViewController.touchIsWithinView(anyFloat(), anyFloat())) |
| .thenReturn(true) |
| whenever(phoneStatusBarViewController.sendTouchToView(downEv)).thenReturn(true) |
| |
| val returnVal = interactionEventHandler.handleDispatchTouchEvent(downEv) |
| |
| verify(phoneStatusBarViewController).sendTouchToView(downEv) |
| assertThat(returnVal).isTrue() |
| } |
| |
| @Test |
| fun handleDispatchTouchEvent_panelNotCollapsed_returnsNull() { |
| underTest.setStatusBarViewController(phoneStatusBarViewController) |
| whenever(statusBarWindowStateController.windowIsShowing()).thenReturn(true) |
| whenever(phoneStatusBarViewController.touchIsWithinView(anyFloat(), anyFloat())) |
| .thenReturn(true) |
| // Item we're testing |
| whenever(notificationPanelViewController.isFullyCollapsed).thenReturn(false) |
| |
| val returnVal = interactionEventHandler.handleDispatchTouchEvent(downEv) |
| |
| verify(phoneStatusBarViewController, never()).sendTouchToView(downEv) |
| assertThat(returnVal).isNull() |
| } |
| |
| @Test |
| fun handleDispatchTouchEvent_touchNotInSbBounds_returnsNull() { |
| underTest.setStatusBarViewController(phoneStatusBarViewController) |
| whenever(statusBarWindowStateController.windowIsShowing()).thenReturn(true) |
| whenever(notificationPanelViewController.isFullyCollapsed).thenReturn(true) |
| // Item we're testing |
| whenever(phoneStatusBarViewController.touchIsWithinView(anyFloat(), anyFloat())) |
| .thenReturn(false) |
| |
| val returnVal = interactionEventHandler.handleDispatchTouchEvent(downEv) |
| |
| verify(phoneStatusBarViewController, never()).sendTouchToView(downEv) |
| assertThat(returnVal).isNull() |
| } |
| |
| @Test |
| fun handleDispatchTouchEvent_sbWindowNotShowing_noSendTouchToSbAndReturnsTrue() { |
| underTest.setStatusBarViewController(phoneStatusBarViewController) |
| whenever(notificationPanelViewController.isFullyCollapsed).thenReturn(true) |
| whenever(phoneStatusBarViewController.touchIsWithinView(anyFloat(), anyFloat())) |
| .thenReturn(true) |
| // Item we're testing |
| whenever(statusBarWindowStateController.windowIsShowing()).thenReturn(false) |
| |
| val returnVal = interactionEventHandler.handleDispatchTouchEvent(downEv) |
| |
| verify(phoneStatusBarViewController, never()).sendTouchToView(downEv) |
| assertThat(returnVal).isTrue() |
| } |
| |
| @Test |
| fun handleDispatchTouchEvent_downEventSentToSbThenAnotherEvent_sendsTouchToSb() { |
| underTest.setStatusBarViewController(phoneStatusBarViewController) |
| whenever(statusBarWindowStateController.windowIsShowing()).thenReturn(true) |
| whenever(notificationPanelViewController.isFullyCollapsed).thenReturn(true) |
| whenever(phoneStatusBarViewController.touchIsWithinView(anyFloat(), anyFloat())) |
| .thenReturn(true) |
| |
| // Down event first |
| interactionEventHandler.handleDispatchTouchEvent(downEv) |
| |
| // Then another event |
| val nextEvent = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_MOVE, 0f, 0f, 0) |
| whenever(phoneStatusBarViewController.sendTouchToView(nextEvent)).thenReturn(true) |
| |
| val returnVal = interactionEventHandler.handleDispatchTouchEvent(nextEvent) |
| |
| verify(phoneStatusBarViewController).sendTouchToView(nextEvent) |
| assertThat(returnVal).isTrue() |
| } |
| |
| @Test |
| fun testLowLightClockAttachedWhenExpandedStatusBarSetup() { |
| verify(lowLightClockController).attachLowLightClockView(ArgumentMatchers.any()) |
| } |
| |
| @Test |
| fun testLowLightClockShownWhenDozing() { |
| underTest.setDozing(true) |
| verify(lowLightClockController).showLowLightClock(true) |
| } |
| |
| @Test |
| fun testLowLightClockDozeTimeTickCalled() { |
| underTest.dozeTimeTick() |
| verify(lowLightClockController).dozeTimeTick() |
| } |
| |
| @Test |
| fun testLowLightClockHiddenWhenNotDozing() { |
| underTest.setDozing(true) |
| verify(lowLightClockController).showLowLightClock(true) |
| underTest.setDozing(false) |
| verify(lowLightClockController).showLowLightClock(false) |
| } |
| } |
| |
| private val downEv = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0) |
| private const val VIEW_BOTTOM = 100 |