Skip to content

Commit

Permalink
Add support for timeouts when calling Fit API in the lib, by using th…
Browse files Browse the repository at this point in the history
…e timeout functionality of PendingResult.
  • Loading branch information
patloew committed Mar 7, 2016
1 parent 207b24e commit f10893e
Show file tree
Hide file tree
Showing 36 changed files with 489 additions and 426 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Changelog

## Version 1.1.0

* BREAKING CHANGE: Removed PermissionRequiredException in favor of SecurityException
* Added `RxFit.checkConnection()` Completable.
* Timeouts can now be provided when creating an Observable. Also, a global default timeout for all Fit API requests made through the lib can be set.
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Reactive Fit API Library for Android

[![Build Status](https://travis-ci.org/patloew/RxFit.svg?branch=master)](https://travis-ci.org/patloew/RxFit) [ ![Download](https://api.bintray.com/packages/patloew/maven/com.patloew.rxfit/images/download.svg) ](https://bintray.com/patloew/maven/com.patloew.rxfit/_latestVersion) [![API](https://img.shields.io/badge/API-9%2B-brightgreen.svg?style=flat)](https://android-arsenal.com/api?level=9)
[![Build Status](https://travis-ci.org/patloew/RxFit.svg?branch=master)](https://travis-ci.org/patloew/RxFit) [![API](https://img.shields.io/badge/API-9%2B-brightgreen.svg?style=flat)](https://android-arsenal.com/api?level=9)

This library wraps the Fit API in [RxJava](https://github.com/ReactiveX/RxJava) Observables. No more managing GoogleApiClients! Also, the authorization process for using fitness data is handled by the lib.

Expand Down Expand Up @@ -31,11 +31,13 @@ RxFit.History.read(dataReadRequest)
});
```

An optional global default timeout for all Fit API requests made through the library can be set via `RxFit.setDefaultTimeout(...)`. In addition, timeouts can be set when creating a new Observable by providing timeout parameters, e.g. `RxFit.History.read(dataReadRequest, 15, TimeUnit.SECONDS)`. These parameters override the default timeout. When a timeout occurs, a StatusException is provided via `onError()`. The RxJava timeout operators can be used instead, but these do not cancel the Fit API request immediately.

You can also obtain an `Observable<GoogleApiClient>`, which connects on subscribe and disconnects on unsubscribe via `GoogleAPIClientObservable.create(...)`.

The following Exceptions are thrown in the lib and provided via `onError()`:

* `StatusException`: When the call to the Fit API was not successful.
* `StatusException`: When the call to the Fit API was not successful or timed out
* `GoogleAPIConnectionException`: When connecting to the GoogleAPIClient was not successful and the resolution (if available) was also not successful (e.g. when the user does not authorize your app to use fitness data). Resolutions are not handled when using `GoogleAPIClientObservable`.
* `GoogleAPIConnectionSuspendedException`: When the GoogleApiClient connection was suspended.
* `SecurityException`: When you try to call a Fit API without proper permissions.
Expand All @@ -49,7 +51,7 @@ A basic sample app is available in the `sample` project. You need to create an O
The lib is available on jCenter. Add the following to your `build.gradle`:

dependencies {
compile 'com.patloew.rxfit:rxfit:1.0.0'
compile 'com.patloew.rxfit:rxfit:1.1.0'
}

# Credits
Expand Down
6 changes: 3 additions & 3 deletions library/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ apply plugin: 'com.jfrog.bintray'
apply plugin: 'com.github.dcendents.android-maven'

group = 'com.patloew.rxfit'
version = '1.0.0'
version = '1.1.0'
project.archivesBaseName = 'rxfit'

android {
Expand All @@ -13,8 +13,8 @@ android {
defaultConfig {
minSdkVersion 9
targetSdkVersion 23
versionCode 1
versionName "1.0.0"
versionCode 2
versionName "1.1.0"
}
buildTypes {
release {
Expand Down
27 changes: 26 additions & 1 deletion library/src/main/java/com/patloew/rxfit/BaseObservable.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,14 @@
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.Api;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.PendingResult;
import com.google.android.gms.common.api.Result;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.common.api.Scope;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

import rx.Observable;
import rx.Observer;
Expand Down Expand Up @@ -49,18 +53,39 @@ public abstract class BaseObservable<T> implements Observable.OnSubscribe<T> {
private GoogleApiClient apiClient;
Subscriber<? super T> subscriber;

protected BaseObservable(@NonNull RxFit rxFit) {
protected final Long timeoutTime;
protected final TimeUnit timeoutUnit;

protected BaseObservable(@NonNull RxFit rxFit, Long timeout, TimeUnit timeUnit) {
this.ctx = rxFit.getContext();
this.services = rxFit.getApis();
this.scopes = rxFit.getScopes();
handleResolution = true;

if(timeout != null && timeUnit != null) {
this.timeoutTime = RxFit.getTimeout(timeout);
this.timeoutUnit = RxFit.getTimeoutUnit(timeUnit);
} else {
this.timeoutTime = RxFit.getTimeout(null);
this.timeoutUnit = RxFit.getTimeoutUnit(null);
}
}

protected BaseObservable(@NonNull Context ctx, @NonNull Api<? extends Api.ApiOptions.NotRequiredOptions>[] services, Scope[] scopes) {
this.ctx = ctx;
this.services = services;
this.scopes = scopes;
handleResolution = false;
timeoutTime = null;
timeoutUnit = null;
}

protected <T extends Result> void setupFitnessPendingResult(PendingResult<T> pendingResult, ResultCallback<? super T> resultCallback) {
if(timeoutTime != null && timeoutUnit != null) {
pendingResult.setResultCallback(resultCallback, timeoutTime, timeoutUnit);
} else {
pendingResult.setResultCallback(resultCallback);
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,43 +1,34 @@
package com.patloew.rxfit;

import android.support.annotation.NonNull;

import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.fitness.Fitness;
import com.google.android.gms.fitness.data.BleDevice;

import rx.Observable;
import java.util.concurrent.TimeUnit;

import rx.Observer;

public class BleClaimDeviceObservable extends BaseObservable<Status> {

private final BleDevice bleDevice;
private final String deviceAddress;

static Observable<Status> create(@NonNull RxFit rxFit, @NonNull BleDevice bleDevice) {
return Observable.create(new BleClaimDeviceObservable(rxFit, bleDevice, null));
}

static Observable<Status> create(@NonNull RxFit rxFit, @NonNull String deviceAddress) {
return Observable.create(new BleClaimDeviceObservable(rxFit, null, deviceAddress));
}

BleClaimDeviceObservable(RxFit rxFit, BleDevice bleDevice, String deviceAddress) {
super(rxFit);
BleClaimDeviceObservable(RxFit rxFit, BleDevice bleDevice, String deviceAddress, Long timeout, TimeUnit timeUnit) {
super(rxFit, timeout, timeUnit);
this.bleDevice = bleDevice;
this.deviceAddress = deviceAddress;
}

@Override
protected void onGoogleApiClientReady(GoogleApiClient apiClient, final Observer<? super Status> observer) {
ResultCallback<Status> resultCallback = new StatusResultCallBack(observer);

if(bleDevice != null) {
Fitness.BleApi.claimBleDevice(apiClient, bleDevice).setResultCallback(resultCallback);
setupFitnessPendingResult(Fitness.BleApi.claimBleDevice(apiClient, bleDevice), resultCallback);
} else {
Fitness.BleApi.claimBleDevice(apiClient, deviceAddress).setResultCallback(resultCallback);
setupFitnessPendingResult(Fitness.BleApi.claimBleDevice(apiClient, deviceAddress), resultCallback);

}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,30 +10,22 @@
import com.google.android.gms.fitness.result.BleDevicesResult;

import java.util.List;
import java.util.concurrent.TimeUnit;

import rx.Observable;
import rx.Observer;

public class BleListClaimedDevicesObservable extends BaseObservable<List<BleDevice>> {

private final DataType dataType;

static Observable<List<BleDevice>> create(@NonNull RxFit rxFit) {
return Observable.create(new BleListClaimedDevicesObservable(rxFit, null));
}

static Observable<List<BleDevice>> create(@NonNull RxFit rxFit, DataType dataType) {
return Observable.create(new BleListClaimedDevicesObservable(rxFit, dataType));
}

BleListClaimedDevicesObservable(RxFit rxFit, DataType dataType) {
super(rxFit);
BleListClaimedDevicesObservable(RxFit rxFit, DataType dataType, Long timeout, TimeUnit timeUnit) {
super(rxFit, timeout, timeUnit);
this.dataType = dataType;
}

@Override
protected void onGoogleApiClientReady(GoogleApiClient apiClient, final Observer<? super List<BleDevice>> observer) {
Fitness.BleApi.listClaimedBleDevices(apiClient).setResultCallback(new ResultCallback<BleDevicesResult>() {
setupFitnessPendingResult(Fitness.BleApi.listClaimedBleDevices(apiClient), new ResultCallback<BleDevicesResult>() {
@Override
public void onResult(@NonNull BleDevicesResult bleDevicesResult) {
if (!bleDevicesResult.getStatus().isSuccess()) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,36 +1,29 @@
package com.patloew.rxfit;

import android.Manifest;
import android.content.pm.PackageManager;
import android.support.annotation.NonNull;
import android.support.annotation.RequiresPermission;
import android.support.v4.content.ContextCompat;

import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.fitness.Fitness;
import com.google.android.gms.fitness.request.StartBleScanRequest;

import rx.Observable;
import java.util.concurrent.TimeUnit;

import rx.Observer;

public class BleStartScanObservable extends BaseObservable<Status> {

private final StartBleScanRequest startBleScanRequest;

@RequiresPermission("android.permission.BLUETOOTH_ADMIN")
static Observable<Status> create(@NonNull RxFit rxFit, @NonNull StartBleScanRequest startBleScanRequest) {
return Observable.create(new BleStartScanObservable(rxFit, startBleScanRequest));
}

BleStartScanObservable(RxFit rxFit, StartBleScanRequest startBleScanRequest) {
super(rxFit);
BleStartScanObservable(RxFit rxFit, StartBleScanRequest startBleScanRequest, Long timeout, TimeUnit timeUnit) {
super(rxFit, timeout, timeUnit);
this.startBleScanRequest = startBleScanRequest;
}

@SuppressWarnings("MissingPermission")
@Override
protected void onGoogleApiClientReady(GoogleApiClient apiClient, final Observer<? super Status> observer) {
//noinspection MissingPermission
Fitness.BleApi.startBleScan(apiClient, startBleScanRequest).setResultCallback(new StatusResultCallBack(observer));
setupFitnessPendingResult(Fitness.BleApi.startBleScan(apiClient, startBleScanRequest), new StatusResultCallBack(observer));
}
}
15 changes: 5 additions & 10 deletions library/src/main/java/com/patloew/rxfit/BleStopScanObservable.java
Original file line number Diff line number Diff line change
@@ -1,30 +1,25 @@
package com.patloew.rxfit;

import android.support.annotation.NonNull;

import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.fitness.Fitness;
import com.google.android.gms.fitness.request.BleScanCallback;

import rx.Observable;
import java.util.concurrent.TimeUnit;

import rx.Observer;

public class BleStopScanObservable extends BaseObservable<Status> {

private final BleScanCallback bleScanCallback;

static Observable<Status> create(@NonNull RxFit rxFit, @NonNull BleScanCallback bleScanCallback) {
return Observable.create(new BleStopScanObservable(rxFit, bleScanCallback));
}

BleStopScanObservable(RxFit rxFit, BleScanCallback bleScanCallback) {
super(rxFit);
BleStopScanObservable(RxFit rxFit, BleScanCallback bleScanCallback, Long timeout, TimeUnit timeUnit) {
super(rxFit, timeout, timeUnit);
this.bleScanCallback = bleScanCallback;
}

@Override
protected void onGoogleApiClientReady(GoogleApiClient apiClient, final Observer<? super Status> observer) {
Fitness.BleApi.stopBleScan(apiClient, bleScanCallback).setResultCallback(new StatusResultCallBack(observer));
setupFitnessPendingResult(Fitness.BleApi.stopBleScan(apiClient, bleScanCallback), new StatusResultCallBack(observer));
}
}
Original file line number Diff line number Diff line change
@@ -1,31 +1,22 @@
package com.patloew.rxfit;

import android.support.annotation.NonNull;

import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.fitness.Fitness;
import com.google.android.gms.fitness.data.BleDevice;

import rx.Observable;
import java.util.concurrent.TimeUnit;

import rx.Observer;

public class BleUnclaimDeviceObservable extends BaseObservable<Status> {

private final BleDevice bleDevice;
private final String deviceAddress;

static Observable<Status> create(@NonNull RxFit rxFit, @NonNull BleDevice bleDevice) {
return Observable.create(new BleUnclaimDeviceObservable(rxFit, bleDevice, null));
}

static Observable<Status> create(@NonNull RxFit rxFit, @NonNull String deviceAddress) {
return Observable.create(new BleUnclaimDeviceObservable(rxFit, null, deviceAddress));
}

BleUnclaimDeviceObservable(RxFit rxFit, BleDevice bleDevice, String deviceAddress) {
super(rxFit);
BleUnclaimDeviceObservable(RxFit rxFit, BleDevice bleDevice, String deviceAddress, Long timeout, TimeUnit timeUnit) {
super(rxFit, timeout, timeUnit);
this.bleDevice = bleDevice;
this.deviceAddress = deviceAddress;
}
Expand All @@ -35,9 +26,9 @@ protected void onGoogleApiClientReady(GoogleApiClient apiClient, final Observer<
ResultCallback<Status> resultCallback = new StatusResultCallBack(observer);

if(bleDevice != null) {
Fitness.BleApi.unclaimBleDevice(apiClient, bleDevice).setResultCallback(resultCallback);
setupFitnessPendingResult(Fitness.BleApi.unclaimBleDevice(apiClient, bleDevice), resultCallback);
} else {
Fitness.BleApi.unclaimBleDevice(apiClient, deviceAddress).setResultCallback(resultCallback);
setupFitnessPendingResult(Fitness.BleApi.unclaimBleDevice(apiClient, deviceAddress), resultCallback);
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.patloew.rxfit;

import com.google.android.gms.common.api.GoogleApiClient;

import rx.Observer;

public class CheckConnectionObservable extends BaseObservable<Void> {

CheckConnectionObservable(RxFit rxFit) {
super(rxFit, null, null);
}

@Override
protected void onGoogleApiClientReady(GoogleApiClient apiClient, Observer<? super Void> observer) {
observer.onCompleted();
}
}
Loading

0 comments on commit f10893e

Please sign in to comment.