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 package com.android.systemui.mediaprojection.taskswitcher.ui.viewmodel 18 19 import android.content.Intent 20 import androidx.test.ext.junit.runners.AndroidJUnit4 21 import androidx.test.filters.SmallTest 22 import com.android.systemui.SysuiTestCase 23 import com.android.systemui.coroutines.collectLastValue 24 import com.android.systemui.kosmos.testScope 25 import com.android.systemui.mediaprojection.taskswitcher.FakeActivityTaskManager.Companion.createTask 26 import com.android.systemui.mediaprojection.taskswitcher.FakeMediaProjectionManager.Companion.createDisplaySession 27 import com.android.systemui.mediaprojection.taskswitcher.FakeMediaProjectionManager.Companion.createSingleTaskSession 28 import com.android.systemui.mediaprojection.taskswitcher.fakeActivityTaskManager 29 import com.android.systemui.mediaprojection.taskswitcher.fakeMediaProjectionManager 30 import com.android.systemui.mediaprojection.taskswitcher.taskSwitcherKosmos 31 import com.android.systemui.mediaprojection.taskswitcher.taskSwitcherViewModel 32 import com.android.systemui.mediaprojection.taskswitcher.ui.model.TaskSwitcherNotificationUiState 33 import com.android.systemui.mediaprojection.taskswitcher.ui.viewmodel.TaskSwitcherNotificationViewModel.Companion.NOTIFICATION_MAX_SHOW_DURATION 34 import com.google.common.truth.Truth.assertThat 35 import kotlin.time.Duration.Companion.milliseconds 36 import kotlinx.coroutines.test.runTest 37 import org.junit.Test 38 import org.junit.runner.RunWith 39 40 @RunWith(AndroidJUnit4::class) 41 @SmallTest 42 class TaskSwitcherNotificationViewModelTest : SysuiTestCase() { 43 44 private val kosmos = taskSwitcherKosmos() 45 private val testScope = kosmos.testScope 46 private val fakeActivityTaskManager = kosmos.fakeActivityTaskManager 47 private val fakeMediaProjectionManager = kosmos.fakeMediaProjectionManager 48 private val viewModel = kosmos.taskSwitcherViewModel 49 50 @Test uiState_notProjecting_emitsNotShowingnull51 fun uiState_notProjecting_emitsNotShowing() = 52 testScope.runTest { 53 val uiState by collectLastValue(viewModel.uiState) 54 55 fakeMediaProjectionManager.dispatchOnStop() 56 57 assertThat(uiState).isEqualTo(TaskSwitcherNotificationUiState.NotShowing) 58 } 59 60 @Test uiState_notProjecting_foregroundTaskChanged_emitsNotShowingnull61 fun uiState_notProjecting_foregroundTaskChanged_emitsNotShowing() = 62 testScope.runTest { 63 val backgroundTask = createTask(taskId = 0) 64 val foregroundTask = createTask(taskId = 1) 65 val uiState by collectLastValue(viewModel.uiState) 66 67 fakeActivityTaskManager.addRunningTasks(backgroundTask, foregroundTask) 68 fakeMediaProjectionManager.dispatchOnStop() 69 fakeActivityTaskManager.moveTaskToForeground(foregroundTask) 70 71 assertThat(uiState).isEqualTo(TaskSwitcherNotificationUiState.NotShowing) 72 } 73 74 @Test uiState_projectingEntireScreen_emitsNotShowingnull75 fun uiState_projectingEntireScreen_emitsNotShowing() = 76 testScope.runTest { 77 val uiState by collectLastValue(viewModel.uiState) 78 79 fakeMediaProjectionManager.dispatchOnSessionSet(session = createDisplaySession()) 80 81 assertThat(uiState).isEqualTo(TaskSwitcherNotificationUiState.NotShowing) 82 } 83 84 @Test uiState_projectingEntireScreen_foregroundTaskChanged_emitsNotShowingnull85 fun uiState_projectingEntireScreen_foregroundTaskChanged_emitsNotShowing() = 86 testScope.runTest { 87 val backgroundTask = createTask(taskId = 0) 88 val foregroundTask = createTask(taskId = 1) 89 val uiState by collectLastValue(viewModel.uiState) 90 91 fakeActivityTaskManager.addRunningTasks(backgroundTask, foregroundTask) 92 fakeMediaProjectionManager.dispatchOnSessionSet(session = createDisplaySession()) 93 fakeActivityTaskManager.moveTaskToForeground(foregroundTask) 94 95 assertThat(uiState).isEqualTo(TaskSwitcherNotificationUiState.NotShowing) 96 } 97 98 @Test uiState_projectingTask_foregroundTaskChanged_different_emitsShowingnull99 fun uiState_projectingTask_foregroundTaskChanged_different_emitsShowing() = 100 testScope.runTest { 101 val projectedTask = createTask(taskId = 1) 102 val foregroundTask = createTask(taskId = 2) 103 val uiState by collectLastValue(viewModel.uiState) 104 105 fakeActivityTaskManager.addRunningTasks(projectedTask, foregroundTask) 106 fakeMediaProjectionManager.dispatchOnSessionSet( 107 session = createSingleTaskSession(projectedTask.token.asBinder()) 108 ) 109 fakeActivityTaskManager.moveTaskToForeground(foregroundTask) 110 111 assertThat(uiState) 112 .isEqualTo(TaskSwitcherNotificationUiState.Showing(projectedTask, foregroundTask)) 113 } 114 115 @Test uiState_taskChanged_beforeDelayLimit_stillEmitsShowingnull116 fun uiState_taskChanged_beforeDelayLimit_stillEmitsShowing() = 117 testScope.runTest { 118 val projectedTask = createTask(taskId = 1) 119 val foregroundTask = createTask(taskId = 2) 120 val uiState by collectLastValue(viewModel.uiState) 121 122 fakeActivityTaskManager.addRunningTasks(projectedTask, foregroundTask) 123 fakeMediaProjectionManager.dispatchOnSessionSet( 124 session = createSingleTaskSession(projectedTask.token.asBinder()) 125 ) 126 fakeActivityTaskManager.moveTaskToForeground(foregroundTask) 127 128 testScheduler.advanceTimeBy(NOTIFICATION_MAX_SHOW_DURATION - 1.milliseconds) 129 assertThat(uiState) 130 .isEqualTo(TaskSwitcherNotificationUiState.Showing(projectedTask, foregroundTask)) 131 } 132 133 @Test uiState_taskChanged_afterDelayLimit_emitsNotShowingnull134 fun uiState_taskChanged_afterDelayLimit_emitsNotShowing() = 135 testScope.runTest { 136 val projectedTask = createTask(taskId = 1) 137 val foregroundTask = createTask(taskId = 2) 138 val uiState by collectLastValue(viewModel.uiState) 139 140 fakeActivityTaskManager.addRunningTasks(projectedTask, foregroundTask) 141 fakeMediaProjectionManager.dispatchOnSessionSet( 142 session = createSingleTaskSession(projectedTask.token.asBinder()) 143 ) 144 fakeActivityTaskManager.moveTaskToForeground(foregroundTask) 145 146 testScheduler.advanceTimeBy(NOTIFICATION_MAX_SHOW_DURATION) 147 assertThat(uiState).isEqualTo(TaskSwitcherNotificationUiState.NotShowing) 148 } 149 150 @Test uiState_projectingTask_foregroundTaskChanged_thenTaskSwitched_emitsNotShowingnull151 fun uiState_projectingTask_foregroundTaskChanged_thenTaskSwitched_emitsNotShowing() = 152 testScope.runTest { 153 val projectedTask = createTask(taskId = 1) 154 val foregroundTask = createTask(taskId = 2) 155 val uiState by collectLastValue(viewModel.uiState) 156 157 fakeActivityTaskManager.addRunningTasks(projectedTask, foregroundTask) 158 fakeMediaProjectionManager.dispatchOnSessionSet( 159 session = createSingleTaskSession(projectedTask.token.asBinder()) 160 ) 161 fakeActivityTaskManager.moveTaskToForeground(foregroundTask) 162 viewModel.onSwitchTaskClicked(foregroundTask) 163 164 assertThat(uiState).isEqualTo(TaskSwitcherNotificationUiState.NotShowing) 165 } 166 167 @Test uiState_projectingTask_foregroundTaskChanged_thenGoBack_emitsNotShowingnull168 fun uiState_projectingTask_foregroundTaskChanged_thenGoBack_emitsNotShowing() = 169 testScope.runTest { 170 val projectedTask = createTask(taskId = 1) 171 val foregroundTask = createTask(taskId = 2) 172 val uiState by collectLastValue(viewModel.uiState) 173 174 fakeActivityTaskManager.addRunningTasks(projectedTask, foregroundTask) 175 fakeMediaProjectionManager.dispatchOnSessionSet( 176 session = createSingleTaskSession(projectedTask.token.asBinder()) 177 ) 178 fakeActivityTaskManager.moveTaskToForeground(foregroundTask) 179 viewModel.onGoBackToTaskClicked(projectedTask) 180 181 assertThat(uiState).isEqualTo(TaskSwitcherNotificationUiState.NotShowing) 182 } 183 184 @Test uiState_projectingTask_foregroundTaskChanged_same_emitsNotShowingnull185 fun uiState_projectingTask_foregroundTaskChanged_same_emitsNotShowing() = 186 testScope.runTest { 187 val projectedTask = createTask(taskId = 1) 188 val uiState by collectLastValue(viewModel.uiState) 189 190 fakeActivityTaskManager.addRunningTasks(projectedTask) 191 fakeMediaProjectionManager.dispatchOnSessionSet( 192 session = createSingleTaskSession(projectedTask.token.asBinder()) 193 ) 194 fakeActivityTaskManager.moveTaskToForeground(projectedTask) 195 196 assertThat(uiState).isEqualTo(TaskSwitcherNotificationUiState.NotShowing) 197 } 198 199 @Test uiState_projectingTask_foregroundTaskChanged_different_taskIsLauncher_emitsNotShowingnull200 fun uiState_projectingTask_foregroundTaskChanged_different_taskIsLauncher_emitsNotShowing() = 201 testScope.runTest { 202 val projectedTask = createTask(taskId = 1) 203 val foregroundTask = createTask(taskId = 2, baseIntent = LAUNCHER_INTENT) 204 val uiState by collectLastValue(viewModel.uiState) 205 206 fakeActivityTaskManager.addRunningTasks(projectedTask, foregroundTask) 207 fakeMediaProjectionManager.dispatchOnSessionSet( 208 session = createSingleTaskSession(projectedTask.token.asBinder()) 209 ) 210 fakeActivityTaskManager.moveTaskToForeground(foregroundTask) 211 212 assertThat(uiState).isEqualTo(TaskSwitcherNotificationUiState.NotShowing) 213 } 214 215 companion object { 216 private val LAUNCHER_INTENT: Intent = 217 Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME) 218 } 219 } 220