• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * 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.display.data.repository
18 
19 import android.hardware.display.DisplayManager
20 import android.os.Looper
21 import android.testing.AndroidTestingRunner
22 import android.testing.TestableLooper
23 import android.view.Display
24 import androidx.test.filters.SmallTest
25 import com.android.systemui.SysuiTestCase
26 import com.android.systemui.coroutines.FlowValue
27 import com.android.systemui.coroutines.collectLastValue
28 import com.android.systemui.util.mockito.eq
29 import com.android.systemui.util.mockito.kotlinArgumentCaptor
30 import com.android.systemui.util.mockito.mock
31 import com.android.systemui.util.mockito.whenever
32 import com.android.systemui.utils.os.FakeHandler
33 import com.google.common.truth.Truth.assertThat
34 import kotlinx.coroutines.ExperimentalCoroutinesApi
35 import kotlinx.coroutines.test.TestScope
36 import kotlinx.coroutines.test.UnconfinedTestDispatcher
37 import kotlinx.coroutines.test.runTest
38 import org.junit.Before
39 import org.junit.Test
40 import org.junit.runner.RunWith
41 import org.mockito.ArgumentMatchers.any
42 import org.mockito.ArgumentMatchers.anyLong
43 import org.mockito.Mockito.never
44 import org.mockito.Mockito.times
45 import org.mockito.Mockito.verify
46 
47 @RunWith(AndroidTestingRunner::class)
48 @TestableLooper.RunWithLooper
49 @OptIn(ExperimentalCoroutinesApi::class)
50 @SmallTest
51 class DisplayRepositoryTest : SysuiTestCase() {
52 
53     private val displayManager = mock<DisplayManager>()
54     private val displayListener = kotlinArgumentCaptor<DisplayManager.DisplayListener>()
55 
56     private val testHandler = FakeHandler(Looper.getMainLooper())
57     private val testScope = TestScope(UnconfinedTestDispatcher())
58 
59     private lateinit var displayRepository: DisplayRepositoryImpl
60 
61     @Before
62     fun setup() {
63         setDisplays(emptyList())
64         displayRepository =
65             DisplayRepositoryImpl(
66                 displayManager,
67                 testHandler,
68                 TestScope(UnconfinedTestDispatcher()),
69                 UnconfinedTestDispatcher()
70             )
71         verify(displayManager, never()).registerDisplayListener(any(), any())
72     }
73 
74     @Test
75     fun onFlowCollection_displayListenerRegistered() =
76         testScope.runTest {
77             val value by latestDisplayFlowValue()
78 
79             assertThat(value).isEmpty()
80 
81             verify(displayManager).registerDisplayListener(any(), eq(testHandler), anyLong())
82         }
83 
84     @Test
85     fun afterFlowCollection_displayListenerUnregistered() {
86         testScope.runTest {
87             val value by latestDisplayFlowValue()
88 
89             assertThat(value).isEmpty()
90 
91             verify(displayManager).registerDisplayListener(any(), eq(testHandler), anyLong())
92         }
93         verify(displayManager).unregisterDisplayListener(any())
94     }
95 
96     @Test
97     fun afterFlowCollection_multipleSusbcriptions_oneRemoved_displayListenerNotUnregistered() {
98         testScope.runTest {
99             val firstSubscriber by latestDisplayFlowValue()
100 
101             assertThat(firstSubscriber).isEmpty()
102             verify(displayManager, times(1))
103                 .registerDisplayListener(displayListener.capture(), eq(testHandler), anyLong())
104 
105             val innerScope = TestScope()
106             innerScope.runTest {
107                 val secondSubscriber by latestDisplayFlowValue()
108                 assertThat(secondSubscriber).isEmpty()
109 
110                 // No new registration, just the precedent one.
111                 verify(displayManager, times(1))
112                     .registerDisplayListener(any(), eq(testHandler), anyLong())
113             }
114 
115             // Let's make sure it has *NOT* been unregistered, as there is still a subscriber.
116             setDisplays(1)
117             displayListener.value.onDisplayAdded(1)
118             assertThat(firstSubscriber?.ids()).containsExactly(1)
119         }
120 
121         // All subscribers are done, unregister should have been called.
122         verify(displayManager).unregisterDisplayListener(any())
123     }
124     @Test
125     fun onDisplayAdded_propagated() =
126         testScope.runTest {
127             val value by latestDisplayFlowValue()
128 
129             setDisplays(1)
130             displayListener.value.onDisplayAdded(1)
131 
132             assertThat(value?.ids()).containsExactly(1)
133         }
134 
135     @Test
136     fun onDisplayRemoved_propagated() =
137         testScope.runTest {
138             val value by latestDisplayFlowValue()
139 
140             setDisplays(1, 2, 3, 4)
141             displayListener.value.onDisplayAdded(1)
142             displayListener.value.onDisplayAdded(2)
143             displayListener.value.onDisplayAdded(3)
144             displayListener.value.onDisplayAdded(4)
145 
146             setDisplays(1, 2, 3)
147             displayListener.value.onDisplayRemoved(4)
148 
149             assertThat(value?.ids()).containsExactly(1, 2, 3)
150         }
151 
152     @Test
153     fun onDisplayChanged_propagated() =
154         testScope.runTest {
155             val value by latestDisplayFlowValue()
156 
157             setDisplays(1, 2, 3, 4)
158             displayListener.value.onDisplayAdded(1)
159             displayListener.value.onDisplayAdded(2)
160             displayListener.value.onDisplayAdded(3)
161             displayListener.value.onDisplayAdded(4)
162 
163             displayListener.value.onDisplayChanged(4)
164 
165             assertThat(value?.ids()).containsExactly(1, 2, 3, 4)
166         }
167 
168     private fun Iterable<Display>.ids(): List<Int> = map { it.displayId }
169 
170     // Wrapper to capture the displayListener.
171     private fun TestScope.latestDisplayFlowValue(): FlowValue<Set<Display>?> {
172         val flowValue = collectLastValue(displayRepository.displays)
173         verify(displayManager)
174             .registerDisplayListener(displayListener.capture(), eq(testHandler), anyLong())
175         return flowValue
176     }
177 
178     private fun setDisplays(displays: List<Display>) {
179         whenever(displayManager.displays).thenReturn(displays.toTypedArray())
180     }
181 
182     private fun setDisplays(vararg ids: Int) {
183         setDisplays(ids.map { display(it) })
184     }
185 
186     private fun display(id: Int): Display {
187         return mock<Display>().also { mockDisplay ->
188             whenever(mockDisplay.displayId).thenReturn(id)
189         }
190     }
191 }
192