1 /*
2  * Copyright (C) 2020 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.broadcast
18 
19 import android.content.BroadcastReceiver
20 import android.content.Context
21 import android.content.Intent
22 import android.content.IntentFilter
23 import android.os.UserHandle
24 import androidx.test.filters.SmallTest
25 import android.testing.AndroidTestingRunner
26 import android.testing.TestableLooper
27 import com.android.systemui.SysuiTestCase
28 import com.android.systemui.broadcast.logging.BroadcastDispatcherLogger
29 import com.android.systemui.util.concurrency.FakeExecutor
30 import com.android.systemui.util.mockito.any
31 import com.android.systemui.util.mockito.capture
32 import com.android.systemui.util.mockito.eq
33 import com.android.systemui.util.time.FakeSystemClock
34 import org.junit.Assert.assertFalse
35 import org.junit.Assert.assertTrue
36 import org.junit.Before
37 import org.junit.Test
38 import org.junit.runner.RunWith
39 import org.mockito.ArgumentCaptor
40 import org.mockito.ArgumentMatchers.anyInt
41 import org.mockito.ArgumentMatchers.anyString
42 import org.mockito.Captor
43 import org.mockito.Mock
44 import org.mockito.Mockito
45 import org.mockito.Mockito.`when`
46 import org.mockito.Mockito.mock
47 import org.mockito.Mockito.never
48 import org.mockito.Mockito.verify
49 import org.mockito.MockitoAnnotations
50 import java.lang.IllegalArgumentException
51 import java.lang.IllegalStateException
52 import java.util.concurrent.Executor
53 
54 @RunWith(AndroidTestingRunner::class)
55 @TestableLooper.RunWithLooper
56 @SmallTest
57 class ActionReceiverTest : SysuiTestCase() {
58 
59     companion object {
60         private const val ACTION1 = "TEST_ACTION1"
61         private const val ACTION2 = "TEST_ACTION2"
62         private const val CATEGORY = "TEST_CATEGORY"
63         private val USER = UserHandle.of(0)
sameNotNullnull64         private fun <T : Any> sameNotNull(arg: T): T = Mockito.same(arg) ?: arg
65 
66         fun IntentFilter.matchesOther(it: IntentFilter): Boolean {
67             val actions = actionsIterator()?.asSequence()?.toSet() ?: emptySet()
68             val categories = categoriesIterator()?.asSequence()?.toSet() ?: emptySet()
69             return (it.actionsIterator()?.asSequence()?.toSet() ?: emptySet()) == actions &&
70                     (it.categoriesIterator()?.asSequence()?.toSet() ?: emptySet()) == categories &&
71                     it.countDataAuthorities() == 0 &&
72                     it.countDataPaths() == 0 &&
73                     it.countDataSchemes() == 0 &&
74                     it.countDataTypes() == 0 &&
75                     it.countMimeGroups() == 0 &&
76                     it.priority == 0
77         }
78     }
79 
80     @Mock
81     private lateinit var registerFunction: BroadcastReceiver.(IntentFilter) -> Unit
82     @Mock
83     private lateinit var unregisterFunction: BroadcastReceiver.() -> Unit
84     @Mock
85     private lateinit var isPendingRemovalFunction: (BroadcastReceiver, Int) -> Boolean
86     @Mock
87     private lateinit var receiver1: BroadcastReceiver
88     @Mock
89     private lateinit var receiver2: BroadcastReceiver
90     @Mock
91     private lateinit var logger: BroadcastDispatcherLogger
92     @Captor
93     private lateinit var intentFilterCaptor: ArgumentCaptor<IntentFilter>
94 
95     private lateinit var executor: FakeExecutor
96     private lateinit var actionReceiver: ActionReceiver
<lambda>null97     private val directExecutor = Executor { it.run() }
98 
99     @Before
setUpnull100     fun setUp() {
101         MockitoAnnotations.initMocks(this)
102         executor = FakeExecutor(FakeSystemClock())
103 
104         `when`(isPendingRemovalFunction(any(), anyInt())).thenReturn(false)
105 
106         actionReceiver = ActionReceiver(
107                 ACTION1,
108                 USER.identifier,
109                 registerFunction,
110                 unregisterFunction,
111                 executor,
112                 logger,
113                 isPendingRemovalFunction
114         )
115     }
116 
117     @Test
testStartsUnregisterednull118     fun testStartsUnregistered() {
119         assertFalse(actionReceiver.registered)
120         verify(registerFunction, never()).invoke(sameNotNull(actionReceiver),
121                 any(IntentFilter::class.java))
122     }
123 
124     @Test
testRegistersOnFirstAddnull125     fun testRegistersOnFirstAdd() {
126         val receiverData = ReceiverData(receiver1, IntentFilter(ACTION1), directExecutor, USER)
127 
128         actionReceiver.addReceiverData(receiverData)
129 
130         assertTrue(actionReceiver.registered)
131         verify(registerFunction).invoke(sameNotNull(actionReceiver), capture(intentFilterCaptor))
132 
133         assertTrue(IntentFilter(ACTION1).matchesOther(intentFilterCaptor.value))
134     }
135 
136     @Test
testRegistersOnlyOncenull137     fun testRegistersOnlyOnce() {
138         val receiverData1 = ReceiverData(receiver1, IntentFilter(ACTION1), directExecutor, USER)
139         val receiverData2 = ReceiverData(receiver2, IntentFilter(ACTION1), directExecutor, USER)
140 
141         actionReceiver.addReceiverData(receiverData1)
142         actionReceiver.addReceiverData(receiverData2)
143 
144         verify(registerFunction).invoke(sameNotNull(actionReceiver), any(IntentFilter::class.java))
145     }
146 
147     @Test
testRemovingLastReceiverUnregistersnull148     fun testRemovingLastReceiverUnregisters() {
149         val receiverData = ReceiverData(receiver1, IntentFilter(ACTION1), directExecutor, USER)
150 
151         actionReceiver.addReceiverData(receiverData)
152 
153         actionReceiver.removeReceiver(receiver1)
154 
155         assertFalse(actionReceiver.registered)
156         verify(unregisterFunction).invoke(sameNotNull(actionReceiver))
157     }
158 
159     @Test
testRemovingWhileOtherReceiversDoesntUnregisternull160     fun testRemovingWhileOtherReceiversDoesntUnregister() {
161         val receiverData1 = ReceiverData(receiver1, IntentFilter(ACTION1), directExecutor, USER)
162         val receiverData2 = ReceiverData(receiver2, IntentFilter(ACTION1), directExecutor, USER)
163 
164         actionReceiver.addReceiverData(receiverData1)
165         actionReceiver.addReceiverData(receiverData2)
166 
167         actionReceiver.removeReceiver(receiver1)
168 
169         assertTrue(actionReceiver.registered)
170         verify(unregisterFunction, never()).invoke(any(BroadcastReceiver::class.java))
171     }
172 
173     @Test
testReceiverHasCategoriesnull174     fun testReceiverHasCategories() {
175         val filter = IntentFilter(ACTION1)
176         filter.addCategory(CATEGORY)
177 
178         val receiverData = ReceiverData(receiver1, filter, directExecutor, USER)
179 
180         actionReceiver.addReceiverData(receiverData)
181 
182         verify(registerFunction).invoke(sameNotNull(actionReceiver), capture(intentFilterCaptor))
183         assertTrue(intentFilterCaptor.value.hasCategory(CATEGORY))
184     }
185 
186     @Test(expected = IllegalArgumentException::class)
testNotRegisteredWithWrongAction_throwsExceptionnull187     fun testNotRegisteredWithWrongAction_throwsException() {
188         val receiverData = ReceiverData(receiver1, IntentFilter(ACTION2), directExecutor, USER)
189 
190         actionReceiver.addReceiverData(receiverData)
191     }
192 
193     @Test
testReceiverGetsBroadcastnull194     fun testReceiverGetsBroadcast() {
195         val receiverData = ReceiverData(receiver1, IntentFilter(ACTION1), directExecutor, USER)
196         actionReceiver.addReceiverData(receiverData)
197 
198         val intent = Intent(ACTION1)
199 
200         actionReceiver.onReceive(mContext, intent)
201 
202         executor.runAllReady()
203 
204         verify(receiver1).onReceive(any(Context::class.java), sameNotNull(intent))
205     }
206 
207     @Test
testReceiverGetsPendingResultnull208     fun testReceiverGetsPendingResult() {
209         val receiverData = ReceiverData(receiver1, IntentFilter(ACTION1), directExecutor, USER)
210         actionReceiver.addReceiverData(receiverData)
211 
212         val intent = Intent(ACTION1)
213         val pendingResult = mock(BroadcastReceiver.PendingResult::class.java)
214 
215         actionReceiver.pendingResult = pendingResult
216         actionReceiver.onReceive(mContext, intent)
217 
218         executor.runAllReady()
219         verify(receiver1).pendingResult = pendingResult
220     }
221 
222     @Test
testBroadcastIsDispatchedInExecutornull223     fun testBroadcastIsDispatchedInExecutor() {
224         val executor = FakeExecutor(FakeSystemClock())
225         val receiverData = ReceiverData(receiver1, IntentFilter(ACTION1), executor, USER)
226         actionReceiver.addReceiverData(receiverData)
227 
228         val intent = Intent(ACTION1)
229         actionReceiver.onReceive(mContext, intent)
230 
231         this.executor.runAllReady()
232 
233         verify(receiver1, never()).onReceive(mContext, intent)
234 
235         executor.runAllReady()
236         // Dispatched after executor is processed
237         verify(receiver1).onReceive(mContext, intent)
238     }
239 
240     @Test
testBroadcastReceivedDispatched_loggernull241     fun testBroadcastReceivedDispatched_logger() {
242         val receiverData = ReceiverData(receiver1, IntentFilter(ACTION1), directExecutor, USER)
243 
244         actionReceiver.addReceiverData(receiverData)
245 
246         val intent = Intent(ACTION1)
247         actionReceiver.onReceive(mContext, intent)
248         verify(logger).logBroadcastReceived(anyInt(), eq(USER.identifier), eq(intent))
249 
250         verify(logger, never()).logBroadcastDispatched(anyInt(), anyString(),
251                 any(BroadcastReceiver::class.java))
252 
253         executor.runAllReady()
254 
255         verify(logger).logBroadcastDispatched(anyInt(), eq(ACTION1), sameNotNull(receiver1))
256     }
257 
258     @Test
testBroadcastNotDispatchingOnPendingRemovalnull259     fun testBroadcastNotDispatchingOnPendingRemoval() {
260         `when`(isPendingRemovalFunction(receiver1, USER.identifier)).thenReturn(true)
261 
262         val receiverData = ReceiverData(receiver1, IntentFilter(ACTION1), directExecutor, USER)
263 
264         actionReceiver.addReceiverData(receiverData)
265 
266         val intent = Intent(ACTION1)
267         actionReceiver.onReceive(mContext, intent)
268         executor.runAllReady()
269         verify(receiver1, never()).onReceive(any(), eq(intent))
270     }
271 
272     @Test(expected = IllegalStateException::class)
testBroadcastWithWrongAction_throwsExceptionnull273     fun testBroadcastWithWrongAction_throwsException() {
274         actionReceiver.onReceive(mContext, Intent(ACTION2))
275     }
276 }