-
Notifications
You must be signed in to change notification settings - Fork 582
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added LocationServicesOkObservable. ( #123 )
Reviewers: pawel.urban Reviewed By: pawel.urban Differential Revision: https://phabricator.polidea.com/D2142
- Loading branch information
1 parent
baefa17
commit 3ad42ec
Showing
5 changed files
with
228 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
79 changes: 79 additions & 0 deletions
79
...droidble/src/main/java/com/polidea/rxandroidble/helpers/LocationServicesOkObservable.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
package com.polidea.rxandroidble.helpers; | ||
|
||
|
||
import android.content.BroadcastReceiver; | ||
import android.content.Context; | ||
import android.content.Intent; | ||
import android.content.IntentFilter; | ||
import android.location.LocationManager; | ||
import android.support.annotation.NonNull; | ||
import com.polidea.rxandroidble.internal.util.CheckerLocationPermission; | ||
import com.polidea.rxandroidble.internal.util.CheckerLocationProvider; | ||
import com.polidea.rxandroidble.internal.util.LocationServicesStatus; | ||
import com.polidea.rxandroidble.internal.util.ProviderApplicationTargetSdk; | ||
import com.polidea.rxandroidble.internal.util.ProviderDeviceSdk; | ||
import java.util.UUID; | ||
import java.util.concurrent.atomic.AtomicBoolean; | ||
import rx.Emitter; | ||
import rx.Observable; | ||
import rx.functions.Action1; | ||
import rx.functions.Cancellable; | ||
import rx.internal.operators.OnSubscribeFromEmitter; | ||
|
||
/** | ||
* An Observable that emits true when {@link com.polidea.rxandroidble.RxBleClient#scanBleDevices(UUID...)} would not | ||
* emit {@link com.polidea.rxandroidble.exceptions.BleScanException} with a reason | ||
* {@link com.polidea.rxandroidble.exceptions.BleScanException#LOCATION_SERVICES_DISABLED} | ||
*/ | ||
public class LocationServicesOkObservable extends Observable<Boolean> { | ||
|
||
public static LocationServicesOkObservable createInstance(@NonNull Context context) { | ||
final Context applicationContext = context.getApplicationContext(); | ||
final LocationManager locationManager = (LocationManager) applicationContext.getSystemService(Context.LOCATION_SERVICE); | ||
final ProviderDeviceSdk providerDeviceSdk = new ProviderDeviceSdk(); | ||
final ProviderApplicationTargetSdk providerApplicationTargetSdk = new ProviderApplicationTargetSdk(applicationContext); | ||
final CheckerLocationPermission checkerLocationPermission = new CheckerLocationPermission(applicationContext); | ||
final CheckerLocationProvider checkerLocationProvider = new CheckerLocationProvider(locationManager); | ||
final LocationServicesStatus locationServicesStatus = new LocationServicesStatus( | ||
checkerLocationProvider, | ||
checkerLocationPermission, | ||
providerDeviceSdk, | ||
providerApplicationTargetSdk | ||
); | ||
return new LocationServicesOkObservable(applicationContext, locationServicesStatus); | ||
} | ||
|
||
LocationServicesOkObservable(@NonNull Context context, @NonNull LocationServicesStatus locationServicesStatus) { | ||
super(new OnSubscribeFromEmitter<>( | ||
new Action1<Emitter<Boolean>>() { | ||
@Override | ||
public void call(Emitter<Boolean> emitter) { | ||
final boolean locationProviderOk = locationServicesStatus.isLocationProviderOk(); | ||
final AtomicBoolean locationProviderOkAtomicBoolean = new AtomicBoolean(locationProviderOk); | ||
emitter.onNext(locationProviderOk); | ||
|
||
BroadcastReceiver broadcastReceiver = new BroadcastReceiver() { | ||
@Override | ||
public void onReceive(Context context, Intent intent) { | ||
final boolean newLocationProviderOkValue = locationServicesStatus.isLocationProviderOk(); | ||
final boolean valueChanged = locationProviderOkAtomicBoolean | ||
.compareAndSet(!newLocationProviderOkValue, newLocationProviderOkValue); | ||
if (valueChanged) { | ||
emitter.onNext(newLocationProviderOkValue); | ||
} | ||
} | ||
}; | ||
|
||
context.registerReceiver(broadcastReceiver, new IntentFilter(LocationManager.PROVIDERS_CHANGED_ACTION)); | ||
emitter.setCancellation(new Cancellable() { | ||
@Override | ||
public void cancel() throws Exception { | ||
context.unregisterReceiver(broadcastReceiver); | ||
} | ||
}); | ||
} | ||
}, | ||
Emitter.BackpressureMode.LATEST | ||
)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
133 changes: 133 additions & 0 deletions
133
.../src/test/groovy/com/polidea/rxandroidble/helpers/LocationServicesOkObservableTest.groovy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
package com.polidea.rxandroidble.helpers | ||
|
||
import android.content.BroadcastReceiver | ||
import android.content.Context | ||
import android.content.Intent | ||
import android.location.LocationManager | ||
import com.polidea.rxandroidble.internal.util.LocationServicesStatus | ||
import org.robolectric.annotation.Config | ||
import org.robospock.RoboSpecification | ||
import rx.Subscription | ||
import rx.observers.TestSubscriber | ||
|
||
@Config(manifest = Config.NONE) | ||
class LocationServicesOkObservableTest extends RoboSpecification { | ||
def contextMock = Mock Context | ||
def mockLocationServicesStatus = Mock LocationServicesStatus | ||
def objectUnderTest = new LocationServicesOkObservable(contextMock, mockLocationServicesStatus) | ||
BroadcastReceiver registeredReceiver | ||
|
||
def setup() { | ||
contextMock.getApplicationContext() >> contextMock | ||
} | ||
|
||
def "should register to correct receiver on subscribe"() { | ||
|
||
given: | ||
mockLocationServicesStatus.isLocationProviderOk() >> true | ||
|
||
when: | ||
objectUnderTest.subscribe() | ||
|
||
then: | ||
1 * contextMock.registerReceiver(!null, { | ||
it.hasAction(LocationManager.PROVIDERS_CHANGED_ACTION) | ||
}) | ||
} | ||
|
||
def "should unregister after observable was unsubscribed"() { | ||
|
||
given: | ||
mockLocationServicesStatus.isLocationProviderOk() >> true | ||
shouldCaptureRegisteredReceiver() | ||
Subscription subscription = objectUnderTest.subscribe() | ||
|
||
when: | ||
subscription.unsubscribe() | ||
|
||
then: | ||
1 * contextMock.unregisterReceiver(registeredReceiver) | ||
} | ||
|
||
def "should emit what LocationServicesStatus.isLocationProviderOk() returns on subscribe and on next broadcasts"() { | ||
|
||
given: | ||
shouldCaptureRegisteredReceiver() | ||
mockLocationServicesStatus.isLocationProviderOk() >>> [true, false, true] | ||
TestSubscriber<Boolean> testSubscriber = new TestSubscriber<>() | ||
|
||
when: | ||
objectUnderTest.subscribe(testSubscriber) | ||
|
||
then: | ||
testSubscriber.assertValue(true) | ||
|
||
when: | ||
postStateChangeBroadcast() | ||
|
||
then: | ||
testSubscriber.assertValues(true, false) | ||
|
||
when: | ||
postStateChangeBroadcast() | ||
|
||
then: | ||
testSubscriber.assertValues(true, false, true) | ||
} | ||
|
||
def "should not emit what LocationServicesStatus.isLocationProviderOk() returns on next broadcasts if the value does not change"() { | ||
|
||
given: | ||
shouldCaptureRegisteredReceiver() | ||
mockLocationServicesStatus.isLocationProviderOk() >>> [false, false, true, true, false, false] | ||
TestSubscriber<Boolean> testSubscriber = new TestSubscriber<>() | ||
|
||
when: | ||
objectUnderTest.subscribe(testSubscriber) | ||
|
||
then: | ||
testSubscriber.assertValue(false) | ||
|
||
when: | ||
postStateChangeBroadcast() | ||
|
||
then: | ||
testSubscriber.assertValue(false) | ||
|
||
when: | ||
postStateChangeBroadcast() | ||
|
||
then: | ||
testSubscriber.assertValues(false, true) | ||
|
||
when: | ||
postStateChangeBroadcast() | ||
|
||
then: | ||
testSubscriber.assertValues(false, true) | ||
|
||
when: | ||
postStateChangeBroadcast() | ||
|
||
then: | ||
testSubscriber.assertValues(false, true, false) | ||
|
||
when: | ||
postStateChangeBroadcast() | ||
|
||
then: | ||
testSubscriber.assertValues(false, true, false) | ||
} | ||
|
||
public postStateChangeBroadcast() { | ||
def intent = new Intent(LocationManager.PROVIDERS_CHANGED_ACTION) | ||
registeredReceiver.onReceive(contextMock, intent) | ||
} | ||
|
||
public BroadcastReceiver shouldCaptureRegisteredReceiver() { | ||
_ * contextMock.registerReceiver({ | ||
BroadcastReceiver receiver -> | ||
this.registeredReceiver = receiver | ||
}, _) | ||
} | ||
} |