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