1 /* 2 * Copyright (C) 2024 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.phone.ongoingcall.domain.interactor 20 21 import android.app.PendingIntent 22 import androidx.test.ext.junit.runners.AndroidJUnit4 23 import androidx.test.filters.SmallTest 24 import com.android.systemui.SysuiTestCase 25 import com.android.systemui.activity.data.repository.activityManagerRepository 26 import com.android.systemui.activity.data.repository.fake 27 import com.android.systemui.coroutines.collectLastValue 28 import com.android.systemui.kosmos.Kosmos 29 import com.android.systemui.kosmos.collectLastValue 30 import com.android.systemui.kosmos.runTest 31 import com.android.systemui.kosmos.useUnconfinedTestDispatcher 32 import com.android.systemui.statusbar.StatusBarIconView 33 import com.android.systemui.statusbar.notification.data.model.activeNotificationModel 34 import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationsStore 35 import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository 36 import com.android.systemui.statusbar.notification.shared.CallType 37 import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallModel 38 import com.google.common.truth.Truth.assertThat 39 import kotlinx.coroutines.ExperimentalCoroutinesApi 40 import kotlinx.coroutines.test.runTest 41 import org.junit.Test 42 import org.junit.runner.RunWith 43 import org.mockito.kotlin.mock 44 45 @SmallTest 46 @RunWith(AndroidJUnit4::class) 47 class OngoingCallInteractorTest : SysuiTestCase() { 48 private val kosmos = Kosmos().useUnconfinedTestDispatcher() 49 private val repository = kosmos.activeNotificationListRepository 50 private val underTest = kosmos.ongoingCallInteractor 51 52 @Test <lambda>null53 fun noNotification_emitsNoCall() = runTest { 54 val state by collectLastValue(underTest.ongoingCallState) 55 assertThat(state).isInstanceOf(OngoingCallModel.NoCall::class.java) 56 } 57 58 @Test ongoingCallNotification_setsNotificationIconAndIntentnull59 fun ongoingCallNotification_setsNotificationIconAndIntent() = 60 kosmos.runTest { 61 val latest by collectLastValue(underTest.ongoingCallState) 62 63 // Set up notification with icon view and intent 64 val testIconView: StatusBarIconView = mock() 65 val testIntent: PendingIntent = mock() 66 repository.activeNotifications.value = 67 ActiveNotificationsStore.Builder() 68 .apply { 69 addIndividualNotif( 70 activeNotificationModel( 71 key = "notif1", 72 whenTime = 1000L, 73 callType = CallType.Ongoing, 74 statusBarChipIcon = testIconView, 75 contentIntent = testIntent 76 ) 77 ) 78 } 79 .build() 80 81 // Verify model is InCall and has the correct icon and intent. 82 assertThat(latest).isInstanceOf(OngoingCallModel.InCall::class.java) 83 val model = latest as OngoingCallModel.InCall 84 assertThat(model.notificationIconView).isSameInstanceAs(testIconView) 85 assertThat(model.intent).isSameInstanceAs(testIntent) 86 } 87 88 @Test ongoingCallNotification_emitsInCallnull89 fun ongoingCallNotification_emitsInCall() = 90 kosmos.runTest { 91 val latest by collectLastValue(underTest.ongoingCallState) 92 93 repository.activeNotifications.value = 94 ActiveNotificationsStore.Builder() 95 .apply { 96 addIndividualNotif( 97 activeNotificationModel( 98 key = "notif1", whenTime = 1000L, callType = CallType.Ongoing 99 ) 100 ) 101 } 102 .build() 103 104 assertThat(latest).isInstanceOf(OngoingCallModel.InCall::class.java) 105 } 106 107 @Test notificationRemoved_emitsNoCallnull108 fun notificationRemoved_emitsNoCall() = 109 kosmos.runTest { 110 val latest by collectLastValue(underTest.ongoingCallState) 111 112 repository.activeNotifications.value = 113 ActiveNotificationsStore.Builder() 114 .apply { 115 addIndividualNotif( 116 activeNotificationModel( 117 key = "notif1", whenTime = 1000L, callType = CallType.Ongoing 118 ) 119 ) 120 } 121 .build() 122 123 repository.activeNotifications.value = ActiveNotificationsStore() 124 assertThat(latest).isInstanceOf(OngoingCallModel.NoCall::class.java) 125 } 126 127 @Test ongoingCallNotification_appVisibleInitially_emitsInCallWithVisibleAppnull128 fun ongoingCallNotification_appVisibleInitially_emitsInCallWithVisibleApp() = 129 kosmos.runTest { 130 kosmos.activityManagerRepository.fake.startingIsAppVisibleValue = true 131 val latest by collectLastValue(underTest.ongoingCallState) 132 133 repository.activeNotifications.value = 134 ActiveNotificationsStore.Builder() 135 .apply { 136 addIndividualNotif( 137 activeNotificationModel( 138 key = "notif1", 139 whenTime = 1000L, 140 callType = CallType.Ongoing, 141 uid = UID 142 ) 143 ) 144 } 145 .build() 146 147 assertThat(latest).isInstanceOf(OngoingCallModel.InCallWithVisibleApp::class.java) 148 } 149 150 @Test ongoingCallNotification_appNotVisibleInitially_emitsInCallnull151 fun ongoingCallNotification_appNotVisibleInitially_emitsInCall() = 152 kosmos.runTest { 153 kosmos.activityManagerRepository.fake.startingIsAppVisibleValue = false 154 val latest by collectLastValue(underTest.ongoingCallState) 155 156 repository.activeNotifications.value = 157 ActiveNotificationsStore.Builder() 158 .apply { 159 addIndividualNotif( 160 activeNotificationModel( 161 key = "notif1", 162 whenTime = 1000L, 163 callType = CallType.Ongoing, 164 uid = UID 165 ) 166 ) 167 } 168 .build() 169 170 assertThat(latest).isInstanceOf(OngoingCallModel.InCall::class.java) 171 } 172 173 @Test ongoingCallNotification_visibilityChanges_updatesStatenull174 fun ongoingCallNotification_visibilityChanges_updatesState() = 175 kosmos.runTest { 176 val latest by collectLastValue(underTest.ongoingCallState) 177 178 // Start with notification and app not visible 179 kosmos.activityManagerRepository.fake.startingIsAppVisibleValue = false 180 repository.activeNotifications.value = 181 ActiveNotificationsStore.Builder() 182 .apply { 183 addIndividualNotif( 184 activeNotificationModel( 185 key = "notif1", 186 whenTime = 1000L, 187 callType = CallType.Ongoing, 188 uid = UID 189 ) 190 ) 191 } 192 .build() 193 assertThat(latest) 194 .isInstanceOf(OngoingCallModel.InCall::class.java) 195 196 // App becomes visible 197 kosmos.activityManagerRepository.fake.setIsAppVisible(UID, true) 198 assertThat(latest).isInstanceOf(OngoingCallModel.InCallWithVisibleApp::class.java) 199 200 // App becomes invisible again 201 kosmos.activityManagerRepository.fake.setIsAppVisible(UID, false) 202 assertThat(latest).isInstanceOf(OngoingCallModel.InCall::class.java) 203 } 204 205 companion object { 206 private const val UID = 885 207 } 208 } 209