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