1/*
2 * Copyright (C) 2006 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
17package android.app.activity;
18
19import android.app.Activity;
20import android.app.ActivityManager;
21import android.content.BroadcastReceiver;
22import android.content.Context;
23import android.content.Intent;
24import android.content.IntentFilter;
25import android.os.Binder;
26import android.os.Bundle;
27import android.os.IBinder;
28import android.os.Parcel;
29import android.os.UserHandle;
30import android.test.FlakyTest;
31import android.test.suitebuilder.annotation.Suppress;
32import android.util.Log;
33
34import java.util.Arrays;
35
36public class BroadcastTest extends ActivityTestsBase {
37    public static final int BROADCAST_TIMEOUT = 5 * 1000;
38
39    public static final String BROADCAST_REGISTERED =
40            "com.android.frameworks.coretests.activity.BROADCAST_REGISTERED";
41    public static final String BROADCAST_LOCAL =
42            "com.android.frameworks.coretests.activity.BROADCAST_LOCAL";
43    public static final String BROADCAST_LOCAL_GRANTED =
44            "com.android.frameworks.coretests.activity.BROADCAST_LOCAL_GRANTED";
45    public static final String BROADCAST_LOCAL_DENIED =
46            "com.android.frameworks.coretests.activity.BROADCAST_LOCAL_DENIED";
47    public static final String BROADCAST_REMOTE =
48            "com.android.frameworks.coretests.activity.BROADCAST_REMOTE";
49    public static final String BROADCAST_REMOTE_GRANTED =
50            "com.android.frameworks.coretests.activity.BROADCAST_REMOTE_GRANTED";
51    public static final String BROADCAST_REMOTE_DENIED =
52            "com.android.frameworks.coretests.activity.BROADCAST_REMOTE_DENIED";
53    public static final String BROADCAST_ALL =
54            "com.android.frameworks.coretests.activity.BROADCAST_ALL";
55    public static final String BROADCAST_MULTI =
56            "com.android.frameworks.coretests.activity.BROADCAST_MULTI";
57    public static final String BROADCAST_ABORT =
58            "com.android.frameworks.coretests.activity.BROADCAST_ABORT";
59
60    public static final String BROADCAST_STICKY1 =
61            "com.android.frameworks.coretests.activity.BROADCAST_STICKY1";
62    public static final String BROADCAST_STICKY2 =
63            "com.android.frameworks.coretests.activity.BROADCAST_STICKY2";
64
65    public static final String BROADCAST_FAIL_REGISTER =
66            "com.android.frameworks.coretests.activity.BROADCAST_FAIL_REGISTER";
67    public static final String BROADCAST_FAIL_BIND =
68            "com.android.frameworks.coretests.activity.BROADCAST_FAIL_BIND";
69
70    public static final String RECEIVER_REG = "receiver-reg";
71    public static final String RECEIVER_LOCAL = "receiver-local";
72    public static final String RECEIVER_REMOTE = "receiver-remote";
73    public static final String RECEIVER_ABORT = "receiver-abort";
74    public static final String RECEIVER_RESULTS = "receiver-results";
75
76    public static final String DATA_1 = "one";
77    public static final String DATA_2 = "two";
78
79    public static final int GOT_RECEIVE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION;
80    public static final int ERROR_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 1;
81
82    private String[] mExpectedReceivers = null;
83    private int mNextReceiver;
84
85    private String[] mExpectedData = null;
86    private boolean[] mReceivedData = null;
87
88    boolean mReceiverRegistered = false;
89
90    public void setExpectedReceivers(String[] receivers) {
91        mExpectedReceivers = receivers;
92        mNextReceiver = 0;
93    }
94
95    public void setExpectedData(String[] data) {
96        mExpectedData = data;
97        mReceivedData = new boolean[data.length];
98    }
99
100    public void onTimeout() {
101        String msg = "Timeout";
102        if (mExpectedReceivers != null && mNextReceiver < mExpectedReceivers.length) {
103            msg = msg + " waiting for " + mExpectedReceivers[mNextReceiver];
104        }
105        finishBad(msg);
106    }
107
108    public Intent makeBroadcastIntent(String action) {
109        Intent intent = new Intent(action, null);
110        intent.putExtra("caller", mCallTarget);
111        return intent;
112    }
113
114    public void finishWithResult(int resultCode, Intent data) {
115        unregisterMyReceiver();
116        super.finishWithResult(resultCode, data);
117    }
118
119    public final void gotReceive(String name, Intent intent) {
120        synchronized (this) {
121
122            //System.out.println("Got receive: " + name);
123            //System.out.println(mNextReceiver + " in " + mExpectedReceivers);
124            //new RuntimeException("stack").printStackTrace();
125
126            addIntermediate(name);
127
128            if (mExpectedData != null) {
129                int n = mExpectedData.length;
130                int i;
131                boolean prev = false;
132                for (i = 0; i < n; i++) {
133                    if (mExpectedData[i].equals(intent.getStringExtra("test"))) {
134                        if (mReceivedData[i]) {
135                            prev = true;
136                            continue;
137                        }
138                        mReceivedData[i] = true;
139                        break;
140                    }
141                }
142                if (i >= n) {
143                    if (prev) {
144                        finishBad("Receive got data too many times: "
145                                + intent.getStringExtra("test"));
146                    } else {
147                        finishBad("Receive got unexpected data: "
148                                + intent.getStringExtra("test"));
149                    }
150                    new RuntimeException("stack").printStackTrace();
151                    return;
152                }
153            }
154
155            if (mNextReceiver >= mExpectedReceivers.length) {
156                finishBad("Got too many onReceiveIntent() calls!");
157//                System.out.println("Too many intents received: now at "
158//                        + mNextReceiver + ", expect list: "
159//                        + Arrays.toString(mExpectedReceivers));
160                fail("Got too many onReceiveIntent() calls!");
161            } else if (!mExpectedReceivers[mNextReceiver].equals(name)) {
162                finishBad("Receive out of order: got " + name
163                        + " but expected "
164                        + mExpectedReceivers[mNextReceiver]);
165                fail("Receive out of order: got " + name
166                        + " but expected "
167                        + mExpectedReceivers[mNextReceiver]);
168            } else {
169                mNextReceiver++;
170                if (mNextReceiver == mExpectedReceivers.length) {
171                    finishTest();
172                }
173            }
174        }
175    }
176
177    public void registerMyReceiver(IntentFilter filter, String permission) {
178        mReceiverRegistered = true;
179        //System.out.println("Registering: " + mReceiver);
180        getContext().registerReceiver(mReceiver, filter, permission, null);
181    }
182
183    public void unregisterMyReceiver() {
184        if (mReceiverRegistered) {
185            unregisterMyReceiverNoCheck();
186        }
187    }
188
189    public void unregisterMyReceiverNoCheck() {
190        mReceiverRegistered = false;
191        //System.out.println("Unregistering: " + mReceiver);
192        getContext().unregisterReceiver(mReceiver);
193    }
194
195    public void onRegisteredReceiver(Intent intent) {
196        gotReceive(RECEIVER_REG, intent);
197    }
198
199    private Binder mCallTarget = new Binder() {
200        public boolean onTransact(int code, Parcel data, Parcel reply,
201                int flags) {
202            data.setDataPosition(0);
203            data.enforceInterface(LaunchpadActivity.LAUNCH);
204            if (code == GOT_RECEIVE_TRANSACTION) {
205                String name = data.readString();
206                gotReceive(name, null);
207                return true;
208            } else if (code == ERROR_TRANSACTION) {
209                finishBad(data.readString());
210                return true;
211            }
212            return false;
213        }
214    };
215
216    private void finishTest() {
217        if (mReceiverRegistered) {
218            addIntermediate("before-unregister");
219            unregisterMyReceiver();
220        }
221        finishTiming(true);
222        finishGood();
223    }
224
225    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
226        public void onReceive(Context context, Intent intent) {
227            //System.out.println("Receive in: " + this + ": " + intent);
228            onRegisteredReceiver(intent);
229        }
230    };
231
232    // Mark flaky until http://b/issue?id=1191607 is resolved.
233    @FlakyTest(tolerance=2)
234    public void testRegistered() throws Exception {
235        runLaunchpad(LaunchpadActivity.BROADCAST_REGISTERED);
236    }
237
238    public void testLocal() throws Exception {
239        runLaunchpad(LaunchpadActivity.BROADCAST_LOCAL);
240    }
241
242    public void testRemote() throws Exception {
243        runLaunchpad(LaunchpadActivity.BROADCAST_REMOTE);
244    }
245
246    public void testAbort() throws Exception {
247        runLaunchpad(LaunchpadActivity.BROADCAST_ABORT);
248    }
249
250    @FlakyTest(tolerance=2)
251    public void testAll() throws Exception {
252        runLaunchpad(LaunchpadActivity.BROADCAST_ALL);
253    }
254
255    @FlakyTest(tolerance=2)
256    public void testMulti() throws Exception {
257        runLaunchpad(LaunchpadActivity.BROADCAST_MULTI);
258    }
259
260    private class TestBroadcastReceiver extends BroadcastReceiver {
261        public boolean mHaveResult = false;
262
263        @Override
264        public void onReceive(Context context, Intent intent) {
265            synchronized (BroadcastTest.this) {
266                mHaveResult = true;
267                BroadcastTest.this.notifyAll();
268            }
269        }
270    }
271
272    public void testResult() throws Exception {
273        TestBroadcastReceiver broadcastReceiver = new TestBroadcastReceiver();
274
275        synchronized (this) {
276            Bundle map = new Bundle();
277            map.putString("foo", "you");
278            map.putString("remove", "me");
279            getContext().sendOrderedBroadcast(
280                    new Intent("com.android.frameworks.coretests.activity.BROADCAST_RESULT"),
281                    null, broadcastReceiver, null, 1, "foo", map);
282            while (!broadcastReceiver.mHaveResult) {
283                try {
284                    wait();
285                } catch (InterruptedException e) {
286                }
287            }
288
289            //System.out.println("Code: " + mResultCode + ", data: " + mResultData);
290            //System.out.println("Extras: " + mResultExtras);
291
292            assertEquals("Incorrect code: " + broadcastReceiver.getResultCode(),
293                    3, broadcastReceiver.getResultCode());
294
295            assertEquals("bar", broadcastReceiver.getResultData());
296
297            Bundle resultExtras = broadcastReceiver.getResultExtras(false);
298            assertEquals("them", resultExtras.getString("bar"));
299            assertEquals("you", resultExtras.getString("foo"));
300            assertNull(resultExtras.getString("remove"));
301        }
302    }
303
304    public void testSetSticky() throws Exception {
305        Intent intent = new Intent(LaunchpadActivity.BROADCAST_STICKY1, null);
306        intent.putExtra("test", LaunchpadActivity.DATA_1);
307        ActivityManager.getService().unbroadcastIntent(null, intent,
308                UserHandle.myUserId());
309
310        ActivityManager.broadcastStickyIntent(intent, UserHandle.myUserId());
311        addIntermediate("finished-broadcast");
312
313        IntentFilter filter = new IntentFilter(LaunchpadActivity.BROADCAST_STICKY1);
314        Intent sticky = getContext().registerReceiver(null, filter);
315        assertNotNull("Sticky not found", sticky);
316        assertEquals(LaunchpadActivity.DATA_1, sticky.getStringExtra("test"));
317    }
318
319    public void testClearSticky() throws Exception {
320        Intent intent = new Intent(LaunchpadActivity.BROADCAST_STICKY1, null);
321        intent.putExtra("test", LaunchpadActivity.DATA_1);
322        ActivityManager.broadcastStickyIntent(intent, UserHandle.myUserId());
323
324        ActivityManager.getService().unbroadcastIntent(
325                null, new Intent(LaunchpadActivity.BROADCAST_STICKY1, null),
326                UserHandle.myUserId());
327        addIntermediate("finished-unbroadcast");
328
329        IntentFilter filter = new IntentFilter(LaunchpadActivity.BROADCAST_STICKY1);
330        Intent sticky = getContext().registerReceiver(null, filter);
331        assertNull("Sticky not found", sticky);
332    }
333
334    public void testReplaceSticky() throws Exception {
335        Intent intent = new Intent(LaunchpadActivity.BROADCAST_STICKY1, null);
336        intent.putExtra("test", LaunchpadActivity.DATA_1);
337        ActivityManager.broadcastStickyIntent(intent, UserHandle.myUserId());
338        intent.putExtra("test", LaunchpadActivity.DATA_2);
339
340        ActivityManager.broadcastStickyIntent(intent, UserHandle.myUserId());
341        addIntermediate("finished-broadcast");
342
343        IntentFilter filter = new IntentFilter(LaunchpadActivity.BROADCAST_STICKY1);
344        Intent sticky = getContext().registerReceiver(null, filter);
345        assertNotNull("Sticky not found", sticky);
346        assertEquals(LaunchpadActivity.DATA_2, sticky.getStringExtra("test"));
347    }
348
349    // Marking flaky until http://b/issue?id=1191337 is resolved
350    @FlakyTest(tolerance=2)
351    public void testReceiveSticky() throws Exception {
352        Intent intent = new Intent(LaunchpadActivity.BROADCAST_STICKY1, null);
353        intent.putExtra("test", LaunchpadActivity.DATA_1);
354        ActivityManager.broadcastStickyIntent(intent, UserHandle.myUserId());
355
356        runLaunchpad(LaunchpadActivity.BROADCAST_STICKY1);
357    }
358
359    // Marking flaky until http://b/issue?id=1191337 is resolved
360    @FlakyTest(tolerance=2)
361    public void testReceive2Sticky() throws Exception {
362        Intent intent = new Intent(LaunchpadActivity.BROADCAST_STICKY1, null);
363        intent.putExtra("test", LaunchpadActivity.DATA_1);
364        ActivityManager.broadcastStickyIntent(intent, UserHandle.myUserId());
365        intent = new Intent(LaunchpadActivity.BROADCAST_STICKY2, null);
366        intent.putExtra("test", LaunchpadActivity.DATA_2);
367        ActivityManager.broadcastStickyIntent(intent, UserHandle.myUserId());
368
369        runLaunchpad(LaunchpadActivity.BROADCAST_STICKY2);
370    }
371
372    public void testRegisteredReceivePermissionGranted() throws Exception {
373        setExpectedReceivers(new String[]{RECEIVER_REG});
374        registerMyReceiver(new IntentFilter(BROADCAST_REGISTERED), PERMISSION_GRANTED);
375        addIntermediate("after-register");
376        getContext().sendBroadcast(makeBroadcastIntent(BROADCAST_REGISTERED));
377        waitForResultOrThrow(BROADCAST_TIMEOUT);
378    }
379
380    public void testRegisteredReceivePermissionDenied() throws Exception {
381        setExpectedReceivers(new String[]{RECEIVER_RESULTS});
382        registerMyReceiver(new IntentFilter(BROADCAST_REGISTERED), PERMISSION_DENIED);
383        addIntermediate("after-register");
384
385        BroadcastReceiver finish = new BroadcastReceiver() {
386            public void onReceive(Context context, Intent intent) {
387                gotReceive(RECEIVER_RESULTS, intent);
388            }
389        };
390
391        getContext().sendOrderedBroadcast(
392                makeBroadcastIntent(BROADCAST_REGISTERED),
393                null, finish, null, Activity.RESULT_CANCELED, null, null);
394        waitForResultOrThrow(BROADCAST_TIMEOUT);
395    }
396
397    public void testRegisteredBroadcastPermissionGranted() throws Exception {
398        setExpectedReceivers(new String[]{RECEIVER_REG});
399        registerMyReceiver(new IntentFilter(BROADCAST_REGISTERED), null);
400        addIntermediate("after-register");
401        getContext().sendBroadcast(
402                makeBroadcastIntent(BROADCAST_REGISTERED),
403                PERMISSION_GRANTED);
404        waitForResultOrThrow(BROADCAST_TIMEOUT);
405    }
406
407    public void testRegisteredBroadcastPermissionDenied() throws Exception {
408        setExpectedReceivers(new String[]{RECEIVER_RESULTS});
409        registerMyReceiver(new IntentFilter(BROADCAST_REGISTERED), null);
410        addIntermediate("after-register");
411
412        BroadcastReceiver finish = new BroadcastReceiver() {
413            public void onReceive(Context context, Intent intent) {
414                gotReceive(RECEIVER_RESULTS, intent);
415            }
416        };
417
418        getContext().sendOrderedBroadcast(
419                makeBroadcastIntent(BROADCAST_REGISTERED),
420                PERMISSION_DENIED, finish, null, Activity.RESULT_CANCELED,
421                null, null);
422        waitForResultOrThrow(BROADCAST_TIMEOUT);
423    }
424
425    public void testLocalReceivePermissionGranted() throws Exception {
426        setExpectedReceivers(new String[]{RECEIVER_LOCAL});
427        getContext().sendBroadcast(makeBroadcastIntent(BROADCAST_LOCAL_GRANTED));
428        waitForResultOrThrow(BROADCAST_TIMEOUT);
429    }
430
431    public void testLocalReceivePermissionDenied() throws Exception {
432        setExpectedReceivers(new String[]{RECEIVER_RESULTS});
433
434        BroadcastReceiver finish = new BroadcastReceiver() {
435            public void onReceive(Context context, Intent intent) {
436                gotReceive(RECEIVER_RESULTS, intent);
437            }
438        };
439
440        getContext().sendOrderedBroadcast(
441                makeBroadcastIntent(BROADCAST_LOCAL_DENIED),
442                null, finish, null, Activity.RESULT_CANCELED,
443                null, null);
444        waitForResultOrThrow(BROADCAST_TIMEOUT);
445    }
446
447    public void testLocalBroadcastPermissionGranted() throws Exception {
448        setExpectedReceivers(new String[]{RECEIVER_LOCAL});
449        getContext().sendBroadcast(
450                makeBroadcastIntent(BROADCAST_LOCAL),
451                PERMISSION_GRANTED);
452        waitForResultOrThrow(BROADCAST_TIMEOUT);
453    }
454
455    public void testLocalBroadcastPermissionDenied() throws Exception {
456        setExpectedReceivers(new String[]{RECEIVER_RESULTS});
457
458        BroadcastReceiver finish = new BroadcastReceiver() {
459            public void onReceive(Context context, Intent intent) {
460                gotReceive(RECEIVER_RESULTS, intent);
461            }
462        };
463
464        getContext().sendOrderedBroadcast(
465                makeBroadcastIntent(BROADCAST_LOCAL),
466                PERMISSION_DENIED, finish, null, Activity.RESULT_CANCELED,
467                null, null);
468        waitForResultOrThrow(BROADCAST_TIMEOUT);
469    }
470
471    public void testRemoteReceivePermissionGranted() throws Exception {
472        setExpectedReceivers(new String[]{RECEIVER_REMOTE});
473        getContext().sendBroadcast(makeBroadcastIntent(BROADCAST_REMOTE_GRANTED));
474        waitForResultOrThrow(BROADCAST_TIMEOUT);
475    }
476
477    public void testRemoteReceivePermissionDenied() throws Exception {
478        setExpectedReceivers(new String[]{RECEIVER_RESULTS});
479
480        BroadcastReceiver finish = new BroadcastReceiver() {
481            public void onReceive(Context context, Intent intent) {
482                gotReceive(RECEIVER_RESULTS, intent);
483            }
484        };
485
486        getContext().sendOrderedBroadcast(
487                makeBroadcastIntent(BROADCAST_REMOTE_DENIED),
488                null, finish, null, Activity.RESULT_CANCELED,
489                null, null);
490        waitForResultOrThrow(BROADCAST_TIMEOUT);
491    }
492
493    public void testRemoteBroadcastPermissionGranted() throws Exception {
494        setExpectedReceivers(new String[]{RECEIVER_REMOTE});
495        getContext().sendBroadcast(
496                makeBroadcastIntent(BROADCAST_REMOTE),
497                PERMISSION_GRANTED);
498        waitForResultOrThrow(BROADCAST_TIMEOUT);
499    }
500
501    public void testRemoteBroadcastPermissionDenied() throws Exception {
502        setExpectedReceivers(new String[]{RECEIVER_RESULTS});
503
504        BroadcastReceiver finish = new BroadcastReceiver() {
505            public void onReceive(Context context, Intent intent) {
506                gotReceive(RECEIVER_RESULTS, intent);
507            }
508        };
509
510        getContext().sendOrderedBroadcast(
511                makeBroadcastIntent(BROADCAST_REMOTE),
512                PERMISSION_DENIED, finish, null, Activity.RESULT_CANCELED,
513                null, null);
514        waitForResultOrThrow(BROADCAST_TIMEOUT);
515    }
516
517    public void testReceiverCanNotRegister() throws Exception {
518        setExpectedReceivers(new String[]{RECEIVER_LOCAL});
519        getContext().sendBroadcast(makeBroadcastIntent(BROADCAST_FAIL_REGISTER));
520        waitForResultOrThrow(BROADCAST_TIMEOUT);
521    }
522
523    public void testReceiverCanNotBind() throws Exception {
524        setExpectedReceivers(new String[]{RECEIVER_LOCAL});
525        getContext().sendBroadcast(makeBroadcastIntent(BROADCAST_FAIL_BIND));
526        waitForResultOrThrow(BROADCAST_TIMEOUT);
527    }
528
529    public void testLocalUnregisterTwice() throws Exception {
530        registerMyReceiver(new IntentFilter(BROADCAST_REGISTERED), null);
531        unregisterMyReceiverNoCheck();
532        try {
533            unregisterMyReceiverNoCheck();
534            fail("No exception thrown on second unregister");
535        } catch (IllegalArgumentException e) {
536            Log.i("foo", "Unregister exception", e);
537        }
538    }
539}
540