1 /*
2  * Copyright (C) 2009 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 android.content.cts;
18 
19 
20 import android.app.Service;
21 import android.content.BroadcastReceiver;
22 import android.content.ComponentName;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.content.IntentFilter;
26 import android.content.ServiceConnection;
27 import android.content.pm.PackageManager;
28 import android.hardware.Camera;
29 import android.os.Bundle;
30 import android.os.IBinder;
31 import android.platform.test.annotations.AppModeFull;
32 import android.test.ActivityInstrumentationTestCase2;
33 
34 /**
35  * Test {@link BroadcastReceiver}.
36  * TODO:  integrate the existing tests.
37  */
38 public class BroadcastReceiverTest extends ActivityInstrumentationTestCase2<MockActivity> {
39     private static final int RESULT_INITIAL_CODE = 1;
40     private static final String RESULT_INITIAL_DATA = "initial data";
41 
42     private static final int RESULT_INTERNAL_FINAL_CODE = 7;
43     private static final String RESULT_INTERNAL_FINAL_DATA = "internal final data";
44 
45     private static final String ACTION_BROADCAST_INTERNAL =
46             "android.content.cts.BroadcastReceiverTest.BROADCAST_INTERNAL";
47     private static final String ACTION_BROADCAST_MOCKTEST =
48             "android.content.cts.BroadcastReceiverTest.BROADCAST_MOCKTEST";
49     private static final String ACTION_BROADCAST_TESTABORT =
50             "android.content.cts.BroadcastReceiverTest.BROADCAST_TESTABORT";
51     private static final String ACTION_BROADCAST_DISABLED =
52             "android.content.cts.BroadcastReceiverTest.BROADCAST_DISABLED";
53     private static final String TEST_PACKAGE_NAME = "android.content.cts";
54 
55     private static final String SIGNATURE_PERMISSION = "android.content.cts.SIGNATURE_PERMISSION";
56 
57     private static final long SEND_BROADCAST_TIMEOUT = 15000;
58     private static final long START_SERVICE_TIMEOUT  = 3000;
59 
60     private static final ComponentName DISABLEABLE_RECEIVER =
61             new ComponentName("android.content.cts",
62                     "android.content.cts.MockReceiverDisableable");
63 
BroadcastReceiverTest()64     public BroadcastReceiverTest() {
65         super(TEST_PACKAGE_NAME, MockActivity.class);
66     }
67 
68     @Override
setUp()69     protected void setUp() throws Exception {
70         super.setUp();
71     }
72 
testConstructor()73     public void testConstructor() {
74         new MockReceiverInternal();
75     }
76 
testAccessDebugUnregister()77     public void testAccessDebugUnregister() {
78         MockReceiverInternal mockReceiver = new MockReceiverInternal();
79         assertFalse(mockReceiver.getDebugUnregister());
80 
81         mockReceiver.setDebugUnregister(true);
82         assertTrue(mockReceiver.getDebugUnregister());
83 
84         mockReceiver.setDebugUnregister(false);
85         assertFalse(mockReceiver.getDebugUnregister());
86     }
87 
testSetOrderedHint()88     public void testSetOrderedHint() {
89         MockReceiverInternal mockReceiver = new MockReceiverInternal();
90 
91         /*
92          * Let's just test to make sure the method doesn't fail for this one.
93          * It's marked as "for internal use".
94          */
95         mockReceiver.setOrderedHint(true);
96         mockReceiver.setOrderedHint(false);
97     }
98 
99     private class MockReceiverInternal extends BroadcastReceiver  {
100         protected boolean mCalledOnReceive = false;
101         private IBinder mIBinder;
102 
103         @Override
onReceive(Context context, Intent intent)104         public synchronized void onReceive(Context context, Intent intent) {
105             mCalledOnReceive = true;
106             Intent serviceIntent = new Intent(context, MockService.class);
107             mIBinder = peekService(context, serviceIntent);
108             notifyAll();
109         }
110 
hasCalledOnReceive()111         public boolean hasCalledOnReceive() {
112             return mCalledOnReceive;
113         }
114 
reset()115         public void reset() {
116             mCalledOnReceive = false;
117         }
118 
waitForReceiver(long timeout)119         public synchronized void waitForReceiver(long timeout)
120                 throws InterruptedException {
121             if (!mCalledOnReceive) {
122                 wait(timeout);
123             }
124             assertTrue(mCalledOnReceive);
125         }
126 
waitForReceiverNoException(long timeout)127         public synchronized boolean waitForReceiverNoException(long timeout)
128                 throws InterruptedException {
129             if (!mCalledOnReceive) {
130                 wait(timeout);
131             }
132             return mCalledOnReceive;
133         }
134 
getIBinder()135         public IBinder getIBinder() {
136             return mIBinder;
137         }
138     }
139 
140     private class MockReceiverInternalOrder extends MockReceiverInternal  {
141         @Override
onReceive(Context context, Intent intent)142         public synchronized void onReceive(Context context, Intent intent) {
143             setResultCode(RESULT_INTERNAL_FINAL_CODE);
144             setResultData(RESULT_INTERNAL_FINAL_DATA);
145 
146             super.onReceive(context, intent);
147         }
148     }
149 
150     private class MockReceiverInternalVerifyUncalled extends MockReceiverInternal {
151         final int mExpectedInitialCode;
152 
MockReceiverInternalVerifyUncalled(int initialCode)153         public MockReceiverInternalVerifyUncalled(int initialCode) {
154             mExpectedInitialCode = initialCode;
155         }
156 
157         @Override
onReceive(Context context, Intent intent)158         public synchronized void onReceive(Context context, Intent intent) {
159             // only update to the expected final values if we're still in the
160             // initial conditions.  The intermediate receiver would have
161             // updated the result code if it [inappropriately] ran.
162             if (getResultCode() == mExpectedInitialCode) {
163                 setResultCode(RESULT_INTERNAL_FINAL_CODE);
164             }
165 
166             super.onReceive(context, intent);
167         }
168     }
169 
testOnReceive()170     public void testOnReceive () throws InterruptedException {
171         final MockActivity activity = getActivity();
172 
173         MockReceiverInternal internalReceiver = new MockReceiverInternal();
174         IntentFilter filter = new IntentFilter();
175         filter.addAction(ACTION_BROADCAST_INTERNAL);
176         activity.registerReceiver(internalReceiver, filter);
177 
178         assertEquals(0, internalReceiver.getResultCode());
179         assertEquals(null, internalReceiver.getResultData());
180         assertEquals(null, internalReceiver.getResultExtras(false));
181 
182         activity.sendBroadcast(new Intent(ACTION_BROADCAST_INTERNAL)
183                 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND));
184         internalReceiver.waitForReceiver(SEND_BROADCAST_TIMEOUT);
185 
186         activity.unregisterReceiver(internalReceiver);
187     }
188 
189     @AppModeFull
testManifestReceiverPackage()190     public void testManifestReceiverPackage() throws InterruptedException {
191         MockReceiverInternal internalReceiver = new MockReceiverInternal();
192 
193         Bundle map = new Bundle();
194         map.putString(MockReceiver.RESULT_EXTRAS_INVARIABLE_KEY,
195                 MockReceiver.RESULT_EXTRAS_INVARIABLE_VALUE);
196         map.putString(MockReceiver.RESULT_EXTRAS_REMOVE_KEY,
197                 MockReceiver.RESULT_EXTRAS_REMOVE_VALUE);
198         getInstrumentation().getContext().sendOrderedBroadcast(
199                 new Intent(ACTION_BROADCAST_MOCKTEST)
200                         .setPackage(TEST_PACKAGE_NAME).addFlags(Intent.FLAG_RECEIVER_FOREGROUND),
201                 null, internalReceiver,
202                 null, RESULT_INITIAL_CODE, RESULT_INITIAL_DATA, map);
203         internalReceiver.waitForReceiver(SEND_BROADCAST_TIMEOUT);
204 
205         // These are set by MockReceiver.
206         assertEquals(MockReceiver.RESULT_CODE, internalReceiver.getResultCode());
207         assertEquals(MockReceiver.RESULT_DATA, internalReceiver.getResultData());
208 
209         Bundle resultExtras = internalReceiver.getResultExtras(false);
210         assertEquals(MockReceiver.RESULT_EXTRAS_INVARIABLE_VALUE,
211                 resultExtras.getString(MockReceiver.RESULT_EXTRAS_INVARIABLE_KEY));
212         assertEquals(MockReceiver.RESULT_EXTRAS_ADD_VALUE,
213                 resultExtras.getString(MockReceiver.RESULT_EXTRAS_ADD_KEY));
214         assertNull(resultExtras.getString(MockReceiver.RESULT_EXTRAS_REMOVE_KEY));
215     }
216 
217     @AppModeFull
testManifestReceiverComponent()218     public void testManifestReceiverComponent() throws InterruptedException {
219         MockReceiverInternal internalReceiver = new MockReceiverInternal();
220 
221         Bundle map = new Bundle();
222         map.putString(MockReceiver.RESULT_EXTRAS_INVARIABLE_KEY,
223                 MockReceiver.RESULT_EXTRAS_INVARIABLE_VALUE);
224         map.putString(MockReceiver.RESULT_EXTRAS_REMOVE_KEY,
225                 MockReceiver.RESULT_EXTRAS_REMOVE_VALUE);
226         getInstrumentation().getContext().sendOrderedBroadcast(
227                 new Intent(ACTION_BROADCAST_MOCKTEST)
228                         .setClass(getActivity(), MockReceiver.class)
229                         .addFlags(Intent.FLAG_RECEIVER_FOREGROUND),
230                 null, internalReceiver,
231                 null, RESULT_INITIAL_CODE, RESULT_INITIAL_DATA, map);
232         internalReceiver.waitForReceiver(SEND_BROADCAST_TIMEOUT);
233 
234         // These are set by MockReceiver.
235         assertEquals(MockReceiver.RESULT_CODE, internalReceiver.getResultCode());
236         assertEquals(MockReceiver.RESULT_DATA, internalReceiver.getResultData());
237 
238         Bundle resultExtras = internalReceiver.getResultExtras(false);
239         assertEquals(MockReceiver.RESULT_EXTRAS_INVARIABLE_VALUE,
240                 resultExtras.getString(MockReceiver.RESULT_EXTRAS_INVARIABLE_KEY));
241         assertEquals(MockReceiver.RESULT_EXTRAS_ADD_VALUE,
242                 resultExtras.getString(MockReceiver.RESULT_EXTRAS_ADD_KEY));
243         assertNull(resultExtras.getString(MockReceiver.RESULT_EXTRAS_REMOVE_KEY));
244     }
245 
246     @AppModeFull
testManifestReceiverPermission()247     public void testManifestReceiverPermission() throws InterruptedException {
248         MockReceiverInternal internalReceiver = new MockReceiverInternal();
249 
250         Bundle map = new Bundle();
251         map.putString(MockReceiver.RESULT_EXTRAS_INVARIABLE_KEY,
252                 MockReceiver.RESULT_EXTRAS_INVARIABLE_VALUE);
253         map.putString(MockReceiver.RESULT_EXTRAS_REMOVE_KEY,
254                 MockReceiver.RESULT_EXTRAS_REMOVE_VALUE);
255         getInstrumentation().getContext().sendOrderedBroadcast(
256                 new Intent(ACTION_BROADCAST_MOCKTEST)
257                         .addFlags(Intent.FLAG_RECEIVER_FOREGROUND),
258                 SIGNATURE_PERMISSION, internalReceiver,
259                 null, RESULT_INITIAL_CODE, RESULT_INITIAL_DATA, map);
260         internalReceiver.waitForReceiver(SEND_BROADCAST_TIMEOUT);
261 
262         // These are set by MockReceiver.
263         assertEquals(MockReceiver.RESULT_CODE, internalReceiver.getResultCode());
264         assertEquals(MockReceiver.RESULT_DATA, internalReceiver.getResultData());
265 
266         Bundle resultExtras = internalReceiver.getResultExtras(false);
267         assertEquals(MockReceiver.RESULT_EXTRAS_INVARIABLE_VALUE,
268                 resultExtras.getString(MockReceiver.RESULT_EXTRAS_INVARIABLE_KEY));
269         assertEquals(MockReceiver.RESULT_EXTRAS_ADD_VALUE,
270                 resultExtras.getString(MockReceiver.RESULT_EXTRAS_ADD_KEY));
271         assertNull(resultExtras.getString(MockReceiver.RESULT_EXTRAS_REMOVE_KEY));
272     }
273 
testNoManifestReceiver()274     public void testNoManifestReceiver() throws InterruptedException {
275         MockReceiverInternal internalReceiver = new MockReceiverInternal();
276 
277         Bundle map = new Bundle();
278         map.putString(MockReceiver.RESULT_EXTRAS_INVARIABLE_KEY,
279                 MockReceiver.RESULT_EXTRAS_INVARIABLE_VALUE);
280         map.putString(MockReceiver.RESULT_EXTRAS_REMOVE_KEY,
281                 MockReceiver.RESULT_EXTRAS_REMOVE_VALUE);
282         getInstrumentation().getContext().sendOrderedBroadcast(
283                 new Intent(ACTION_BROADCAST_MOCKTEST).addFlags(Intent.FLAG_RECEIVER_FOREGROUND),
284                 null, internalReceiver,
285                 null, RESULT_INITIAL_CODE, RESULT_INITIAL_DATA, map);
286         internalReceiver.waitForReceiver(SEND_BROADCAST_TIMEOUT);
287 
288         // The MockReceiver should not have run, so we should still have the initial result.
289         assertEquals(RESULT_INITIAL_CODE, internalReceiver.getResultCode());
290         assertEquals(RESULT_INITIAL_DATA, internalReceiver.getResultData());
291 
292         Bundle resultExtras = internalReceiver.getResultExtras(false);
293         assertEquals(MockReceiver.RESULT_EXTRAS_INVARIABLE_VALUE,
294                 resultExtras.getString(MockReceiver.RESULT_EXTRAS_INVARIABLE_KEY));
295         assertNull(resultExtras.getString(MockReceiver.RESULT_EXTRAS_ADD_KEY));
296         assertEquals(MockReceiver.RESULT_EXTRAS_REMOVE_VALUE,
297                 resultExtras.getString(MockReceiver.RESULT_EXTRAS_REMOVE_KEY));
298     }
299 
300     @AppModeFull
testAbortBroadcast()301     public void testAbortBroadcast() throws InterruptedException {
302         MockReceiverInternalOrder internalOrderReceiver = new MockReceiverInternalOrder();
303 
304         assertEquals(0, internalOrderReceiver.getResultCode());
305         assertNull(internalOrderReceiver.getResultData());
306         assertNull(internalOrderReceiver.getResultExtras(false));
307 
308         Bundle map = new Bundle();
309         map.putString(MockReceiver.RESULT_EXTRAS_INVARIABLE_KEY,
310                 MockReceiver.RESULT_EXTRAS_INVARIABLE_VALUE);
311         map.putString(MockReceiver.RESULT_EXTRAS_REMOVE_KEY,
312                 MockReceiver.RESULT_EXTRAS_REMOVE_VALUE);
313         // The order of the receiver is:
314         // MockReceiverFirst --> MockReceiverAbort --> MockReceiver --> internalOrderReceiver.
315         // And MockReceiver is the receiver which will be aborted.
316         getInstrumentation().getContext().sendOrderedBroadcast(
317                 new Intent(ACTION_BROADCAST_TESTABORT)
318                         .setPackage(TEST_PACKAGE_NAME).addFlags(Intent.FLAG_RECEIVER_FOREGROUND),
319                 null, internalOrderReceiver,
320                 null, RESULT_INITIAL_CODE, RESULT_INITIAL_DATA, map);
321         internalOrderReceiver.waitForReceiver(SEND_BROADCAST_TIMEOUT);
322 
323         assertEquals(RESULT_INTERNAL_FINAL_CODE, internalOrderReceiver.getResultCode());
324         assertEquals(RESULT_INTERNAL_FINAL_DATA, internalOrderReceiver.getResultData());
325         Bundle resultExtras = internalOrderReceiver.getResultExtras(false);
326         assertEquals(MockReceiver.RESULT_EXTRAS_INVARIABLE_VALUE,
327                 resultExtras.getString(MockReceiver.RESULT_EXTRAS_INVARIABLE_KEY));
328         assertEquals(MockReceiver.RESULT_EXTRAS_REMOVE_VALUE,
329                 resultExtras.getString(MockReceiver.RESULT_EXTRAS_REMOVE_KEY));
330         assertEquals(MockReceiverFirst.RESULT_EXTRAS_FIRST_VALUE,
331                 resultExtras.getString(MockReceiverFirst.RESULT_EXTRAS_FIRST_KEY));
332         assertEquals(MockReceiverAbort.RESULT_EXTRAS_ABORT_VALUE,
333                 resultExtras.getString(MockReceiverAbort.RESULT_EXTRAS_ABORT_KEY));
334     }
335 
testDisabledBroadcastReceiver()336     public void testDisabledBroadcastReceiver() throws Exception {
337         final Context context = getInstrumentation().getContext();
338         PackageManager pm = context.getPackageManager();
339 
340         MockReceiverInternalVerifyUncalled lastReceiver =
341                 new MockReceiverInternalVerifyUncalled(RESULT_INITIAL_CODE);
342         assertEquals(0, lastReceiver.getResultCode());
343 
344         pm.setComponentEnabledSetting(DISABLEABLE_RECEIVER,
345                 PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
346                 PackageManager.DONT_KILL_APP);
347 
348         context.sendOrderedBroadcast(
349                 new Intent(ACTION_BROADCAST_DISABLED).addFlags(Intent.FLAG_RECEIVER_FOREGROUND),
350                 null, lastReceiver,
351                 null, RESULT_INITIAL_CODE, RESULT_INITIAL_DATA, new Bundle());
352         lastReceiver.waitForReceiver(SEND_BROADCAST_TIMEOUT);
353 
354         assertEquals(RESULT_INTERNAL_FINAL_CODE, lastReceiver.getResultCode());
355     }
356 
testPeekService()357     public void testPeekService() throws InterruptedException {
358         final MockActivity activity = getActivity();
359 
360         MockReceiverInternal internalReceiver = new MockReceiverInternal();
361         IntentFilter filter = new IntentFilter();
362         filter.addAction(ACTION_BROADCAST_INTERNAL);
363         activity.registerReceiver(internalReceiver, filter);
364 
365         activity.sendBroadcast(new Intent(ACTION_BROADCAST_INTERNAL)
366                 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND));
367         internalReceiver.waitForReceiver(SEND_BROADCAST_TIMEOUT);
368         assertNull(internalReceiver.getIBinder());
369 
370         Intent intent = new Intent(activity, MockService.class);
371         MyServiceConnection msc = new MyServiceConnection();
372         assertTrue(activity.bindService(intent, msc, Service.BIND_AUTO_CREATE));
373         assertTrue(msc.waitForService(START_SERVICE_TIMEOUT));
374 
375         internalReceiver.reset();
376         activity.sendBroadcast(new Intent(ACTION_BROADCAST_INTERNAL)
377                 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND));
378         internalReceiver.waitForReceiver(SEND_BROADCAST_TIMEOUT);
379         assertNotNull(internalReceiver.getIBinder());
380         activity.unbindService(msc);
381         activity.stopService(intent);
382         activity.unregisterReceiver(internalReceiver);
383     }
384 
testNewPhotoBroadcast_notReceived()385     public void testNewPhotoBroadcast_notReceived() throws InterruptedException {
386         final MockActivity activity = getActivity();
387         MockReceiverInternal internalReceiver = new MockReceiverInternal();
388         IntentFilter filter = new IntentFilter();
389         filter.addAction(Camera.ACTION_NEW_PICTURE);
390         activity.registerReceiver(internalReceiver, filter);
391         assertFalse(internalReceiver.waitForReceiverNoException(SEND_BROADCAST_TIMEOUT));
392     }
393 
testNewVideoBroadcast_notReceived()394     public void testNewVideoBroadcast_notReceived() throws InterruptedException {
395         final MockActivity activity = getActivity();
396         MockReceiverInternal internalReceiver = new MockReceiverInternal();
397         IntentFilter filter = new IntentFilter();
398         filter.addAction(Camera.ACTION_NEW_VIDEO);
399         activity.registerReceiver(internalReceiver, filter);
400         assertFalse(internalReceiver.waitForReceiverNoException(SEND_BROADCAST_TIMEOUT));
401     }
402 
403     static class MyServiceConnection implements ServiceConnection {
404         private boolean serviceConnected;
405 
onServiceConnected(ComponentName name, IBinder service)406         public synchronized void onServiceConnected(ComponentName name, IBinder service) {
407             serviceConnected = true;
408             notifyAll();
409         }
410 
onServiceDisconnected(ComponentName name)411         public synchronized void onServiceDisconnected(ComponentName name) {
412         }
413 
waitForService(long timeout)414         public synchronized boolean waitForService(long timeout) {
415             if (!serviceConnected) {
416                 try {
417                     wait(timeout);
418                 } catch (InterruptedException ignored) {
419                     // ignored
420                 }
421             }
422             return serviceConnected;
423         }
424     }
425 }
426