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 package com.android.systemui.car.displayconfig
18 
19 import android.testing.AndroidTestingRunner
20 import android.testing.TestableLooper.RunWithLooper
21 import android.view.Display
22 import androidx.test.filters.SmallTest
23 import com.android.systemui.SysuiTestCase
24 import com.android.systemui.car.CarSystemUiTest
25 import com.android.systemui.display.data.repository.DisplayRepository
26 import com.android.systemui.display.data.repository.DisplayRepository.PendingDisplay
27 import com.android.systemui.process.ProcessWrapper
28 import kotlinx.coroutines.ExperimentalCoroutinesApi
29 import kotlinx.coroutines.cancelChildren
30 import kotlinx.coroutines.flow.Flow
31 import kotlinx.coroutines.flow.MutableStateFlow
32 import kotlinx.coroutines.flow.StateFlow
33 import kotlinx.coroutines.flow.emptyFlow
34 import kotlinx.coroutines.flow.flowOf
35 import kotlinx.coroutines.launch
36 import kotlinx.coroutines.test.StandardTestDispatcher
37 import kotlinx.coroutines.test.TestScope
38 import kotlinx.coroutines.test.advanceUntilIdle
39 import kotlinx.coroutines.test.runTest
40 import org.junit.Test
41 import org.junit.runner.RunWith
42 import org.mockito.kotlin.mock
43 import org.mockito.kotlin.never
44 import org.mockito.kotlin.verify
45 import org.mockito.kotlin.whenever
46 
47 @CarSystemUiTest
48 @RunWith(AndroidTestingRunner::class)
49 @RunWithLooper
50 @SmallTest
51 class ExternalDisplayControllerTest : SysuiTestCase() {
52 
53     private val testScope = TestScope()
54     private val bgDispatcher =
55         StandardTestDispatcher(testScope.testScheduler, name = "Background dispatcher")
56     private val pendingDisplayMock: PendingDisplay = mock()
57     private val fakePendingDisplayFlow = flowOf(null, pendingDisplayMock)
58     private val fakeDisplayRepository = FakeDisplayRepository(fakePendingDisplayFlow)
59     private val processWrapper: ProcessWrapper = mock()
60 
61     private val externalDisplayController = ExternalDisplayController(
62         fakeDisplayRepository,
63         processWrapper,
64         testScope,
65         bgDispatcher
66     )
67 
68     @OptIn(ExperimentalCoroutinesApi::class)
69     @Test
<lambda>null70     fun start_whenSystemUser_enablesPendingDisplays() = testScope.runTest() {
71         whenever(processWrapper.isSystemUser).thenReturn(true)
72 
73         launch(StandardTestDispatcher(testScheduler)) {
74             externalDisplayController.start()
75         }
76         advanceUntilIdle()
77         coroutineContext.cancelChildren()
78 
79         verify(pendingDisplayMock).enable()
80     }
81 
82     @OptIn(ExperimentalCoroutinesApi::class)
83     @Test
<lambda>null84     fun start_whenNonSystemUser_noOp() = testScope.runTest {
85         whenever(processWrapper.isSystemUser).thenReturn(false)
86 
87         launch(StandardTestDispatcher(testScheduler)) {
88             externalDisplayController.start()
89         }
90         advanceUntilIdle()
91         coroutineContext.cancelChildren()
92 
93         verify(pendingDisplayMock, never()).enable()
94     }
95 }
96 
97 class FakeDisplayRepository(
98     private val fakePendingDisplayFlow: Flow<PendingDisplay?>,
99     override val displayChangeEvent: Flow<Int> = emptyFlow(),
100     override val displayAdditionEvent: Flow<Display?> = emptyFlow(),
101     override val displayRemovalEvent: Flow<Int> = emptyFlow(),
102     override val displays: StateFlow<Set<Display>> = MutableStateFlow(emptySet()),
103     override val defaultDisplayOff: Flow<Boolean> = emptyFlow(),
104     override val pendingDisplay: Flow<PendingDisplay?> = fakePendingDisplayFlow,
105     override val displayIds: StateFlow<Set<Int>> = MutableStateFlow(emptySet()),
106 ) : DisplayRepository
107