Skip to content

Commit 27a56dc

Browse files
Merge pull request ReactiveX#1528 from Yarikx/android-broadcasts-rebased
Add operators to create Observables from BroadcastReceiver (rebased)
2 parents 400a611 + 7d10c7e commit 27a56dc

File tree

8 files changed

+375
-9
lines changed

8 files changed

+375
-9
lines changed

rxjava-contrib/rxjava-android-samples/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ buildscript {
55
mavenCentral()
66
}
77
dependencies {
8-
classpath 'com.android.tools.build:gradle:0.11.+'
8+
classpath 'com.android.tools.build:gradle:0.12.+'
99
}
1010
}
1111

rxjava-contrib/rxjava-android-samples/samples/build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
apply plugin: 'android'
1+
apply plugin: 'com.android.application'
22

33
android {
44
compileSdkVersion 19
5-
buildToolsVersion "19.1.0"
5+
buildToolsVersion "20"
66

77
defaultConfig {
88
minSdkVersion 14

rxjava-contrib/rxjava-android/build.gradle

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ dependencies {
88
// testing
99
testCompile 'junit:junit-dep:4.10'
1010
testCompile 'org.mockito:mockito-core:1.8.5'
11-
testCompile 'org.robolectric:robolectric:2.2'
11+
testCompile('org.robolectric:robolectric:2.3') {
12+
exclude group: 'com.android.support'
13+
}
1214
}
1315

1416
javadoc {

rxjava-contrib/rxjava-android/src/main/java/rx/android/observables/AndroidObservable.java

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,22 @@
1515
*/
1616
package rx.android.observables;
1717

18-
import static rx.android.schedulers.AndroidSchedulers.mainThread;
18+
import android.app.Activity;
19+
import android.app.Fragment;
20+
import android.content.Context;
21+
import android.content.Intent;
22+
import android.content.IntentFilter;
23+
import android.os.Build;
24+
import android.os.Handler;
1925

2026
import rx.Observable;
2127
import rx.functions.Func1;
22-
import rx.operators.OperatorObserveFromAndroidComponent;
28+
import rx.operators.OperatorBroadcastRegister;
2329
import rx.operators.OperatorConditionalBinding;
30+
import rx.operators.OperatorLocalBroadcastRegister;
31+
import rx.operators.OperatorObserveFromAndroidComponent;
2432

25-
import android.app.Activity;
26-
import android.app.Fragment;
27-
import android.os.Build;
33+
import static rx.android.schedulers.AndroidSchedulers.mainThread;
2834

2935

3036
public final class AndroidObservable {
@@ -176,4 +182,37 @@ public static <T> Observable<T> bindFragment(Object fragment, Observable<T> sour
176182
throw new IllegalArgumentException("Target fragment is neither a native nor support library Fragment");
177183
}
178184
}
185+
186+
/**
187+
* Create Observable that wraps BroadcastReceiver and emmit received intents.
188+
*
189+
* @param filter Selects the Intent broadcasts to be received.
190+
*/
191+
public static Observable<Intent> fromBroadcast(Context context, IntentFilter filter){
192+
return Observable.create(new OperatorBroadcastRegister(context, filter, null, null));
193+
}
194+
195+
/**
196+
* Create Observable that wraps BroadcastReceiver and emmit received intents.
197+
*
198+
* @param filter Selects the Intent broadcasts to be received.
199+
* @param broadcastPermission String naming a permissions that a
200+
* broadcaster must hold in order to send an Intent to you. If null,
201+
* no permission is required.
202+
* @param schedulerHandler Handler identifying the thread that will receive
203+
* the Intent. If null, the main thread of the process will be used.
204+
*/
205+
public static Observable<Intent> fromBroadcast(Context context, IntentFilter filter, String broadcastPermission, Handler schedulerHandler){
206+
return Observable.create(new OperatorBroadcastRegister(context, filter, broadcastPermission, schedulerHandler));
207+
}
208+
209+
/**
210+
* Create Observable that wraps BroadcastReceiver and connects to LocalBroadcastManager
211+
* to emmit received intents.
212+
*
213+
* @param filter Selects the Intent broadcasts to be received.
214+
*/
215+
public static Observable<Intent> fromLocalBroadcast(Context context, IntentFilter filter){
216+
return Observable.create(new OperatorLocalBroadcastRegister(context, filter));
217+
}
179218
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/**
2+
* Copyright 2014 Netflix, Inc.
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+
package rx.operators;
17+
18+
import android.content.BroadcastReceiver;
19+
import android.content.Context;
20+
import android.content.Intent;
21+
import android.content.IntentFilter;
22+
import android.os.Handler;
23+
24+
import rx.Observable;
25+
import rx.Subscriber;
26+
import rx.Subscription;
27+
import rx.functions.Action0;
28+
import rx.subscriptions.Subscriptions;
29+
30+
public class OperatorBroadcastRegister implements Observable.OnSubscribe<Intent> {
31+
32+
private final Context context;
33+
private final IntentFilter intentFilter;
34+
private final String broadcastPermission;
35+
private final Handler schedulerHandler;
36+
37+
public OperatorBroadcastRegister(Context context, IntentFilter intentFilter, String broadcastPermission, Handler schedulerHandler) {
38+
this.context = context;
39+
this.intentFilter = intentFilter;
40+
this.broadcastPermission = broadcastPermission;
41+
this.schedulerHandler = schedulerHandler;
42+
}
43+
44+
@Override
45+
public void call(final Subscriber<? super Intent> subscriber) {
46+
final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
47+
@Override
48+
public void onReceive(Context context, Intent intent) {
49+
subscriber.onNext(intent);
50+
}
51+
};
52+
53+
final Subscription subscription = Subscriptions.create(new Action0() {
54+
@Override
55+
public void call() {
56+
context.unregisterReceiver(broadcastReceiver);
57+
}
58+
});
59+
60+
subscriber.add(subscription);
61+
context.registerReceiver(broadcastReceiver, intentFilter, broadcastPermission, schedulerHandler);
62+
63+
}
64+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/**
2+
* Copyright 2014 Netflix, Inc.
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+
package rx.operators;
17+
18+
import android.content.BroadcastReceiver;
19+
import android.content.Context;
20+
import android.content.Intent;
21+
import android.content.IntentFilter;
22+
import android.support.v4.content.LocalBroadcastManager;
23+
24+
import rx.Observable;
25+
import rx.Subscriber;
26+
import rx.Subscription;
27+
import rx.android.subscriptions.AndroidSubscriptions;
28+
import rx.functions.Action0;
29+
import rx.subscriptions.Subscriptions;
30+
31+
public class OperatorLocalBroadcastRegister implements Observable.OnSubscribe<Intent> {
32+
33+
private final Context context;
34+
private final IntentFilter intentFilter;
35+
36+
public OperatorLocalBroadcastRegister(Context context, IntentFilter intentFilter) {
37+
this.context = context;
38+
this.intentFilter = intentFilter;
39+
}
40+
41+
@Override
42+
public void call(final Subscriber<? super Intent> subscriber) {
43+
final LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(context);
44+
final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
45+
@Override
46+
public void onReceive(Context context, Intent intent) {
47+
subscriber.onNext(intent);
48+
}
49+
};
50+
51+
final Subscription subscription = Subscriptions.create(new Action0() {
52+
@Override
53+
public void call() {
54+
localBroadcastManager.unregisterReceiver(broadcastReceiver);
55+
}
56+
});
57+
58+
subscriber.add(subscription);
59+
localBroadcastManager.registerReceiver(broadcastReceiver, intentFilter);
60+
}
61+
}
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
/**
2+
* Copyright 2014 Netflix, Inc.
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+
package rx.android.operators;
17+
18+
import android.app.Application;
19+
import android.content.Intent;
20+
import android.content.IntentFilter;
21+
22+
import org.junit.Test;
23+
import org.junit.runner.RunWith;
24+
import org.mockito.InOrder;
25+
import org.robolectric.Robolectric;
26+
import org.robolectric.RobolectricTestRunner;
27+
28+
import rx.Observable;
29+
import rx.Observer;
30+
import rx.Subscription;
31+
import rx.android.observables.AndroidObservable;
32+
import rx.observers.TestObserver;
33+
34+
import static org.mockito.Matchers.any;
35+
import static org.mockito.Mockito.inOrder;
36+
import static org.mockito.Mockito.mock;
37+
import static org.mockito.Mockito.never;
38+
import static org.mockito.Mockito.times;
39+
40+
@RunWith(RobolectricTestRunner.class)
41+
public class OperatorBroadcastRegisterTest {
42+
43+
@Test
44+
public void testBroadcast() {
45+
String action = "TEST_ACTION";
46+
IntentFilter intentFilter = new IntentFilter(action);
47+
Application application = Robolectric.application;
48+
Observable<Intent> observable = AndroidObservable.fromBroadcast(application, intentFilter);
49+
final Observer<Intent> observer = mock(Observer.class);
50+
final Subscription subscription = observable.subscribe(new TestObserver<Intent>(observer));
51+
52+
final InOrder inOrder = inOrder(observer);
53+
54+
inOrder.verify(observer, never()).onNext(any(Intent.class));
55+
56+
Intent intent = new Intent(action);
57+
application.sendBroadcast(intent);
58+
inOrder.verify(observer, times(1)).onNext(intent);
59+
60+
application.sendBroadcast(intent);
61+
inOrder.verify(observer, times(1)).onNext(intent);
62+
63+
subscription.unsubscribe();
64+
application.sendBroadcast(intent);
65+
inOrder.verify(observer, never()).onNext(any(Intent.class));
66+
67+
inOrder.verify(observer, never()).onError(any(Throwable.class));
68+
inOrder.verify(observer, never()).onCompleted();
69+
}
70+
71+
@Test
72+
public void testStickyBroadcast() {
73+
String action = "TEST_STICKY_ACTION";
74+
IntentFilter intentFilter = new IntentFilter(action);
75+
Application application = Robolectric.application;
76+
Intent intent = new Intent(action);
77+
application.sendStickyBroadcast(intent);
78+
Observable<Intent> observable = AndroidObservable.fromBroadcast(application, intentFilter);
79+
final Observer<Intent> observer = mock(Observer.class);
80+
final Subscription subscription = observable.subscribe(new TestObserver<Intent>(observer));
81+
82+
final InOrder inOrder = inOrder(observer);
83+
84+
inOrder.verify(observer, times(1)).onNext(intent);
85+
86+
application.sendBroadcast(intent);
87+
inOrder.verify(observer, times(1)).onNext(intent);
88+
89+
subscription.unsubscribe();
90+
application.sendBroadcast(intent);
91+
inOrder.verify(observer, never()).onNext(any(Intent.class));
92+
93+
inOrder.verify(observer, never()).onError(any(Throwable.class));
94+
inOrder.verify(observer, never()).onCompleted();
95+
}
96+
97+
@Test
98+
public void testPermissionBroadcast() {
99+
String action = "TEST_ACTION";
100+
String permission = "test_permission";
101+
IntentFilter intentFilter = new IntentFilter(action);
102+
Application application = Robolectric.application;
103+
Observable<Intent> observable = AndroidObservable.fromBroadcast(application, intentFilter, permission, null);
104+
final Observer<Intent> observer = mock(Observer.class);
105+
final Subscription subscription = observable.subscribe(new TestObserver<Intent>(observer));
106+
107+
final InOrder inOrder = inOrder(observer);
108+
109+
inOrder.verify(observer, never()).onNext(any(Intent.class));
110+
111+
Intent intent = new Intent(action);
112+
application.sendBroadcast(intent);
113+
inOrder.verify(observer, never()).onNext(intent);
114+
115+
application.sendBroadcast(intent, permission);
116+
inOrder.verify(observer, times(1)).onNext(intent);
117+
118+
subscription.unsubscribe();
119+
application.sendBroadcast(intent);
120+
application.sendBroadcast(intent, permission);
121+
inOrder.verify(observer, never()).onNext(any(Intent.class));
122+
123+
inOrder.verify(observer, never()).onError(any(Throwable.class));
124+
inOrder.verify(observer, never()).onCompleted();
125+
}
126+
127+
}

0 commit comments

Comments
 (0)