1 /* 2 * Copyright (C) 2023 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 @file:OptIn(ExperimentalCoroutinesApi::class) 18 19 package com.android.systemui.statusbar.notification.shelf.ui.viewmodel 20 21 import android.os.PowerManager 22 import android.testing.AndroidTestingRunner 23 import androidx.test.filters.SmallTest 24 import com.android.systemui.SysuiTestCase 25 import com.android.systemui.accessibility.data.repository.FakeAccessibilityRepository 26 import com.android.systemui.accessibility.domain.interactor.AccessibilityInteractor 27 import com.android.systemui.classifier.FalsingCollectorFake 28 import com.android.systemui.coroutines.collectLastValue 29 import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFaceAuthRepository 30 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository 31 import com.android.systemui.plugins.statusbar.StatusBarStateController 32 import com.android.systemui.power.data.repository.FakePowerRepository 33 import com.android.systemui.power.domain.interactor.PowerInteractor 34 import com.android.systemui.statusbar.LockscreenShadeTransitionController 35 import com.android.systemui.statusbar.notification.row.ui.viewmodel.ActivatableNotificationViewModel 36 import com.android.systemui.statusbar.notification.shelf.domain.interactor.NotificationShelfInteractor 37 import com.android.systemui.statusbar.phone.ScreenOffAnimationController 38 import com.android.systemui.util.mockito.eq 39 import com.android.systemui.util.mockito.whenever 40 import com.google.common.truth.Truth.assertThat 41 import kotlinx.coroutines.ExperimentalCoroutinesApi 42 import kotlinx.coroutines.test.runTest 43 import org.junit.Before 44 import org.junit.Rule 45 import org.junit.Test 46 import org.junit.runner.RunWith 47 import org.mockito.Mock 48 import org.mockito.Mockito 49 import org.mockito.Mockito.verify 50 import org.mockito.junit.MockitoJUnit 51 import org.mockito.junit.MockitoRule 52 53 @RunWith(AndroidTestingRunner::class) 54 @SmallTest 55 class NotificationShelfViewModelTest : SysuiTestCase() { 56 57 @Rule @JvmField val mockitoRule: MockitoRule = MockitoJUnit.rule() 58 59 // mocks 60 @Mock private lateinit var keyguardTransitionController: LockscreenShadeTransitionController 61 @Mock private lateinit var screenOffAnimationController: ScreenOffAnimationController 62 @Mock private lateinit var statusBarStateController: StatusBarStateController 63 64 // fakes 65 private val keyguardRepository = FakeKeyguardRepository() 66 private val deviceEntryFaceAuthRepository = FakeDeviceEntryFaceAuthRepository() 67 private val a11yRepo = FakeAccessibilityRepository() 68 private val powerRepository = FakePowerRepository() 69 private val powerInteractor by lazy { 70 PowerInteractor( 71 powerRepository, 72 keyguardRepository, 73 FalsingCollectorFake(), 74 screenOffAnimationController, 75 statusBarStateController, 76 ) 77 } 78 79 // real impls 80 private val a11yInteractor = AccessibilityInteractor(a11yRepo) 81 private val activatableViewModel = ActivatableNotificationViewModel(a11yInteractor) 82 private val interactor by lazy { 83 NotificationShelfInteractor( 84 keyguardRepository, 85 deviceEntryFaceAuthRepository, 86 powerInteractor, 87 keyguardTransitionController, 88 ) 89 } 90 private val underTest by lazy { NotificationShelfViewModel(interactor, activatableViewModel) } 91 92 @Before 93 fun setUp() { 94 whenever(screenOffAnimationController.allowWakeUpIfDozing()).thenReturn(true) 95 } 96 97 @Test 98 fun canModifyColorOfNotifications_whenKeyguardNotShowing() = runTest { 99 val canModifyNotifColor by collectLastValue(underTest.canModifyColorOfNotifications) 100 101 keyguardRepository.setKeyguardShowing(false) 102 103 assertThat(canModifyNotifColor).isTrue() 104 } 105 106 @Test 107 fun canModifyColorOfNotifications_whenKeyguardShowingAndNotBypass() = runTest { 108 val canModifyNotifColor by collectLastValue(underTest.canModifyColorOfNotifications) 109 110 keyguardRepository.setKeyguardShowing(true) 111 deviceEntryFaceAuthRepository.isBypassEnabled.value = false 112 113 assertThat(canModifyNotifColor).isTrue() 114 } 115 116 @Test 117 fun cannotModifyColorOfNotifications_whenBypass() = runTest { 118 val canModifyNotifColor by collectLastValue(underTest.canModifyColorOfNotifications) 119 120 keyguardRepository.setKeyguardShowing(true) 121 deviceEntryFaceAuthRepository.isBypassEnabled.value = true 122 123 assertThat(canModifyNotifColor).isFalse() 124 } 125 126 @Test 127 fun isClickable_whenKeyguardShowing() = runTest { 128 val isClickable by collectLastValue(underTest.isClickable) 129 130 keyguardRepository.setKeyguardShowing(true) 131 132 assertThat(isClickable).isTrue() 133 } 134 135 @Test 136 fun isNotClickable_whenKeyguardNotShowing() = runTest { 137 val isClickable by collectLastValue(underTest.isClickable) 138 139 keyguardRepository.setKeyguardShowing(false) 140 141 assertThat(isClickable).isFalse() 142 } 143 144 @Test 145 fun onClicked_goesToLockedShade() { 146 whenever(statusBarStateController.isDozing).thenReturn(true) 147 148 underTest.onShelfClicked() 149 150 assertThat(powerRepository.lastWakeReason).isNotNull() 151 assertThat(powerRepository.lastWakeReason).isEqualTo(PowerManager.WAKE_REASON_GESTURE) 152 verify(keyguardTransitionController).goToLockedShade(Mockito.isNull(), eq(true)) 153 } 154 } 155