Skip to content

Commit

Permalink
Merge pull request #83 from OvalMoney/release/0.5.0
Browse files Browse the repository at this point in the history
Release/0.5.0
  • Loading branch information
franceto authored Nov 22, 2020
2 parents e08d652 + eae21ab commit 7783bfd
Show file tree
Hide file tree
Showing 13 changed files with 247 additions and 139 deletions.
43 changes: 31 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,15 +59,21 @@ In order to make it run, it is necessary to turn on `Health Kit` in the `Capabil
```java
compile project(':@ovalmoney_react-native-fitness')
```

5. (Optional) In order to better handle the right versions, add in your `android/build.gradle`:
```ext {
// Other build versions
fitnessPlayServices: "<Your version>" // default: 17.0.0
authPlayServices: "<Your version>" // default: 17.0.0
}
```

## Usage

```javascript
import Fitness from '@ovalmoney/react-native-fitness';

const permissions = [
{ kind: Fitness.PermissionKind.Step, access: Fitness.PermissionAccess.Write },
{ kind: Fitness.PermissionKinds.Steps, access: Fitness.PermissionAccesses.Write },
];

Fitness.isAuthorized(permissions)
Expand All @@ -83,19 +89,27 @@ Fitness.isAuthorized(permissions)
- **Fitness.isAuthorized([{ kind: int, access: int }])**
Check if permissions are granted or not. It works on Android and iOS >= 12.0, while it returns an error when iOS < 12.
It requires an `Array` of `Object` with a mandatory key `kind` and an optional key `access`.
Possible values for the keys can be found in `PermissionKind` and `PermissionAccess` under `Attributes` section.
Possible values for the keys can be found in `PermissionKinds` and `PermissionAccesses` under `Attributes` section.
On iOS at least one permissions with `Read` access must be provided, otherwise an `errorEmptyPermissions` will be thrown.

- **Fitness.requestPermissions([{ kind: int, access: int }])**
Ask permission and return if user granted or not(Android), while, due to Apple's privacy model, always true is returned in iOS.
It requires an `Array` of `Object` with a mandatory key `kind` and an optional key `access`.
Possible values for the keys can be found in `PermissionKind` and `PermissionAccess` under `Attributes` section.
Possible values for the keys can be found in `PermissionKinds` and `PermissionAccesses` under `Attributes` section.
On iOS at least one permissions with `Read` access must be provided, otherwise an `errorEmptyPermissions` will be thrown.

- **Fitness.logout()**
Available only on android. It performs a logout from google account.
It returns `true` for a successful logout, `false` if user cancel action.

- **Fitness.disconnect()**
Available only on android. It performs a disconnect action from Google Fit.
It returns `true` for a successful logout, `false` if user cancel action.

- **Fitness.getSteps({ startDate: string, endDate: string, interval: string })**
Fetch steps on a given period of time. It requires an `Object` with `startDate` and `endDate` attributes as string. If startDate is not provided an error will be thrown. Set `interval` to decide how detailed the returned data is, set it to `hour` or `minute` otherwise it defaults to `days`.

- **Fitness.getDistance({ startDate: string, endDate: string, interval: string })**
- **Fitness.getDistances({ startDate: string, endDate: string, interval: string })**
Fetch distance in meters on a given period of time. It requires an `Object` with `startDate` and `endDate` attributes as string. If startDate is not provided an error will be thrown. Set `interval` to decide how detailed the returned data is, set it to `hour` or `minute` otherwise it defaults to `days`.

- **Fitness.getCalories({ startDate: string, endDate: string, interval: string })**
Expand All @@ -120,31 +134,36 @@ Call this function to get steps and eliminate the need to have Google Fit instal
#### Platform
Return the used provider.

#### PermissionKind
#### PermissionKinds
Return the information of what kind of Permission can be asked.
At the moment the list of possible kinds is:
- ***Step***: to required the access for `Step`
- ***Distance***: to required the access for `Distances`
- ***Steps***: to required the access for `Steps`
- ***Distances***: to required the access for `Distances`
- ***Calories***: to required the access for `Calories`
- ***HeartRate***: to required the access for `Heart rate`
- ***Activity***: to required the access for `Activity` (only Android)
- ***SleepAnalysis***: to required the access for `Sleep Analysis`


#### PermissionAccess
#### PermissionAccesses
Return the information of what kind of Access can be asked.
The list of possible kinds is:
- ***Read***: to required the access to `Read`
- ***Write***: to required the access to `Write`

#### Error (iOS only)
#### Errors
Return the list of meaningful errors that can be possible thrown.
On Android it is an empty object.

##### iOS
Possible values are:
- ***hkNotAvailable***: thrown if HealthKit is not available
- ***methodNotAvailable***: thrown if `isAuthorized` is called on iOS < 12.0
- ***dateNotCorrect***: thrown if received date is not correct
- ***dateNotCorrect***: thrown if received date is not correct
- ***errorEmptyPermissions***: thrown if no read permissions are provided
- ***errorNoEvents***: thrown if an error occurs while try to retrieve data

##### Android
Possible values are:
- ***methodNotAvailable***: thrown if `getSleepAnalysis` is called on Android less than N


10 changes: 5 additions & 5 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ def safeExtGet(prop, fallback) {

apply plugin: 'com.android.library'

def DEFAULT_COMPILE_SDK_VERSION = 28
def DEFAULT_BUILD_TOOLS_VERSION = "28.0.3"
def DEFAULT_TARGET_SDK_VERSION = 28
def DEFAULT_COMPILE_SDK_VERSION = 29
def DEFAULT_BUILD_TOOLS_VERSION = "29.0.2"
def DEFAULT_TARGET_SDK_VERSION = 29

android {
compileSdkVersion safeExtGet('compileSdkVersion', DEFAULT_COMPILE_SDK_VERSION)
Expand All @@ -39,6 +39,6 @@ repositories {

dependencies {
implementation 'com.facebook.react:react-native:+'
implementation "com.google.android.gms:play-services-fitness:${safeExtGet('googlePlayServicesVersion', '17.0.0')}"
implementation "com.google.android.gms:play-services-auth:${safeExtGet('googlePlayServicesVersion', '17.0.0')}"
implementation "com.google.android.gms:play-services-fitness:${safeExtGet('fitnessPlayServices', '17.0.0')}"
implementation "com.google.android.gms:play-services-auth:${safeExtGet('authPlayServices', '17.0.0')}"
}
52 changes: 37 additions & 15 deletions android/src/main/java/com/ovalmoney/fitness/RNFitnessModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.Promise;
import com.ovalmoney.fitness.manager.FitnessError;
import com.ovalmoney.fitness.permission.Permission;
import com.ovalmoney.fitness.permission.Permissions;
import com.ovalmoney.fitness.permission.Request;

public class RNFitnessModule extends ReactContextBaseJavaModule{
Expand All @@ -25,21 +25,21 @@ public class RNFitnessModule extends ReactContextBaseJavaModule{
private final static String PLATFORM_KEY = "Platform";
private final static String PLATFORM = "GoogleFit";

private final static String ERROR_KEY = "Error";
private final static String ERRORS_KEY = "Errors";
private final static String ERROR_METHOD_NOT_AVAILABLE_KEY = "methodNotAvailable";

private final static String PERMISSIONS_KEY = "PermissionKind";
private final static String STEP_KEY = "Step";
private final static String PERMISSIONS_KEY = "PermissionKinds";
private final static String STEPS_KEY = "Steps";
private final static String ACTIVITY_KEY = "Activity";
private final static String CALORIES_KEY = "Calories";
private final static String DISTANCE_KEY = "Distance";
private final static String DISTANCES_KEY = "Distances";
private final static String HEART_RATE_KEY = "HeartRate";
private final static String SLEEP_ANALYSIS_KEY = "SleepAnalysis";

private final static String ACCESS_TYPE_KEY = "PermissionAccess";
private final static String ACCESS_TYPE_KEY = "PermissionAccesses";

private final static String READ = "READ";
private final static String WRITE = "WRITE";
private final static String READ = "Read";
private final static String WRITE = "Write";

private final static Map<String, Integer> PERMISSIONS = new HashMap<>();
private final static Map<String, Integer> ACCESSES = new HashMap<>();
Expand All @@ -51,17 +51,18 @@ public RNFitnessModule(ReactApplicationContext reactContext) {
super(reactContext);
feedPermissionsMap();
feedAccessesTypeMap();
feedErrorsMap();
this.manager = new Manager();
reactContext.addActivityEventListener(this.manager);
}

private void feedPermissionsMap(){
PERMISSIONS.put(STEP_KEY, Permission.STEP);
PERMISSIONS.put(DISTANCE_KEY, Permission.DISTANCE);
PERMISSIONS.put(ACTIVITY_KEY, Permission.ACTIVITY);
PERMISSIONS.put(CALORIES_KEY, Permission.CALORIES);
PERMISSIONS.put(HEART_RATE_KEY, Permission.HEART_RATE);
PERMISSIONS.put(SLEEP_ANALYSIS_KEY, Permission.SLEEP_ANALYSIS);
PERMISSIONS.put(STEPS_KEY, Permissions.STEPS);
PERMISSIONS.put(DISTANCES_KEY, Permissions.DISTANCES);
PERMISSIONS.put(ACTIVITY_KEY, Permissions.ACTIVITY);
PERMISSIONS.put(CALORIES_KEY, Permissions.CALORIES);
PERMISSIONS.put(HEART_RATE_KEY, Permissions.HEART_RATE);
PERMISSIONS.put(SLEEP_ANALYSIS_KEY, Permissions.SLEEP_ANALYSIS);
}

private void feedAccessesTypeMap(){
Expand All @@ -84,7 +85,7 @@ public Map<String, Object> getConstants() {
constants.put(PLATFORM_KEY, PLATFORM);
constants.put(PERMISSIONS_KEY, PERMISSIONS);
constants.put(ACCESS_TYPE_KEY, ACCESSES);
constants.put(ERROR_KEY, ERRORS);
constants.put(ERRORS_KEY, ERRORS);
return constants;
}

Expand All @@ -103,6 +104,27 @@ public void requestPermissions(ReadableArray permissions, Promise promise){
}
}


@ReactMethod
public void logout(Promise promise){
final Activity activity = getCurrentActivity();
if(activity != null) {
manager.logout(activity, promise);
}else{
promise.reject(new Throwable());
}
}

@ReactMethod
public void disconnect(Promise promise){
final Activity activity = getCurrentActivity();
if(activity != null) {
manager.disconnect(activity, promise);
}else{
promise.reject(new Throwable());
}
}

@ReactMethod
public void subscribeToActivity(Promise promise){
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,5 @@
})

public @interface FitnessError {
int ERROR_METHOD_NOT_AVAILABLE = -101;
int ERROR_METHOD_NOT_AVAILABLE = -99;
}
81 changes: 69 additions & 12 deletions android/src/main/java/com/ovalmoney/fitness/manager/Manager.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.nfc.Tag;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;

import androidx.annotation.NonNull;
Expand All @@ -18,6 +16,7 @@
import com.facebook.react.bridge.WritableMap;
import com.google.android.gms.auth.api.signin.GoogleSignIn;
import com.google.android.gms.auth.api.signin.GoogleSignInAccount;
import com.google.android.gms.auth.api.signin.GoogleSignInOptions;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability;
import com.google.android.gms.fitness.Fitness;
Expand All @@ -37,8 +36,8 @@
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.android.gms.tasks.OnCanceledListener;
import com.google.android.gms.tasks.Task;
import com.google.android.gms.fitness.data.Subscription;
import com.ovalmoney.fitness.permission.Request;

import java.text.DateFormat;
Expand All @@ -50,12 +49,12 @@
import java.util.function.Predicate;
import java.util.stream.Collectors;

import static com.ovalmoney.fitness.permission.Permission.ACTIVITY;
import static com.ovalmoney.fitness.permission.Permission.CALORIES;
import static com.ovalmoney.fitness.permission.Permission.DISTANCE;
import static com.ovalmoney.fitness.permission.Permission.STEP;
import static com.ovalmoney.fitness.permission.Permission.HEART_RATE;
import static com.ovalmoney.fitness.permission.Permission.SLEEP_ANALYSIS;
import static com.ovalmoney.fitness.permission.Permissions.ACTIVITY;
import static com.ovalmoney.fitness.permission.Permissions.CALORIES;
import static com.ovalmoney.fitness.permission.Permissions.DISTANCES;
import static com.ovalmoney.fitness.permission.Permissions.STEPS;
import static com.ovalmoney.fitness.permission.Permissions.HEART_RATE;
import static com.ovalmoney.fitness.permission.Permissions.SLEEP_ANALYSIS;

public class Manager implements ActivityEventListener {

Expand Down Expand Up @@ -92,12 +91,12 @@ protected FitnessOptions.Builder addPermissionToFitnessOptions(final FitnessOpti
for(int i = 0; i < length; i++){
Request currentRequest = permissions.get(i);
switch(currentRequest.permissionKind){
case STEP:
case STEPS:
fitnessOptions
.addDataType(DataType.TYPE_STEP_COUNT_DELTA, currentRequest.permissionAccess)
.addDataType(DataType.TYPE_STEP_COUNT_CUMULATIVE, currentRequest.permissionAccess);
break;
case DISTANCE:
case DISTANCES:
fitnessOptions.addDataType(DataType.TYPE_DISTANCE_DELTA, currentRequest.permissionAccess);
break;
case CALORIES:
Expand All @@ -109,6 +108,7 @@ protected FitnessOptions.Builder addPermissionToFitnessOptions(final FitnessOpti
case HEART_RATE:
fitnessOptions.addDataType(DataType.TYPE_HEART_RATE_BPM, currentRequest.permissionAccess);
break;
case SLEEP_ANALYSIS:
default:
break;
}
Expand All @@ -119,7 +119,7 @@ protected FitnessOptions.Builder addPermissionToFitnessOptions(final FitnessOpti

public boolean isAuthorized(final Activity activity, final ArrayList<Request> permissions){
if(isGooglePlayServicesAvailable(activity)) {
FitnessOptions fitnessOptions = addPermissionToFitnessOptions(FitnessOptions.builder(), permissions)
final FitnessOptions fitnessOptions = addPermissionToFitnessOptions(FitnessOptions.builder(), permissions)
.build();
return GoogleSignIn.hasPermissions(GoogleSignIn.getLastSignedInAccount(activity), fitnessOptions);
}
Expand Down Expand Up @@ -151,6 +151,63 @@ public void onActivityResult(Activity activity, int requestCode, int resultCode,
}
}


public void logout(@NonNull Activity currentActivity, final Promise promise) {
final GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN).build();
GoogleSignIn.getClient(currentActivity, gso)
.revokeAccess()
.addOnCanceledListener(new OnCanceledListener() {
@Override
public void onCanceled() {
promise.resolve(false);
}
})
.addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
promise.resolve(true);
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
promise.reject(e);
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
promise.reject(e);
}
});
}

public void disconnect(@NonNull Activity currentActivity, final Promise promise) {
Fitness.getConfigClient(
currentActivity,
GoogleSignIn.getLastSignedInAccount(currentActivity.getApplicationContext()
))
.disableFit()
.addOnCanceledListener(new OnCanceledListener() {
@Override
public void onCanceled() {
promise.resolve(false);
}
})
.addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
promise.resolve(true);
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
promise.reject(e);
}
});
}

@Override
public void onNewIntent(Intent intent) { }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,17 @@

@Retention(SOURCE)
@IntDef({
Permission.STEP,
Permission.DISTANCE,
Permission.ACTIVITY,
Permission.CALORIES,
Permission.SLEEP_ANALYSIS,
Permissions.STEPS,
Permissions.DISTANCES,
Permissions.ACTIVITY,
Permissions.CALORIES,
Permissions.HEART_RATE,
Permissions.SLEEP_ANALYSIS,
})

public @interface Permission {
int STEP = 0;
int DISTANCE = 1;
public @interface Permissions {
int STEPS = 0;
int DISTANCES = 1;
int ACTIVITY = 2;
int CALORIES = 3;
int HEART_RATE = 4;
Expand Down
Loading

0 comments on commit 7783bfd

Please sign in to comment.