package com.ybrain.rn.googlefitness; import android.app.Activity; import android.app.Dialog; import android.support.annotation.NonNull; import android.util.Log; import com.facebook.react.bridge.LifecycleEventListener; import com.facebook.react.bridge.Promise; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactMethod; import com.facebook.react.bridge.WritableNativeArray; import com.facebook.react.bridge.WritableNativeMap; 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.GoogleApiAvailability; import com.google.android.gms.fitness.Fitness; import com.google.android.gms.fitness.FitnessOptions; import com.google.android.gms.fitness.HistoryClient; import com.google.android.gms.fitness.data.DataSet; import com.google.android.gms.fitness.data.DataType; import com.google.android.gms.fitness.request.DataDeleteRequest; import com.google.android.gms.fitness.request.DataReadRequest; import com.google.android.gms.fitness.request.DataUpdateRequest; import com.google.android.gms.fitness.result.DataReadResponse; import com.google.android.gms.tasks.Continuation; import com.google.android.gms.tasks.OnFailureListener; import com.google.android.gms.tasks.OnSuccessListener; import com.google.android.gms.tasks.Task; import com.ybrain.jsoninterpreter.StatementFactory; import com.ybrain.jsoninterpreter.statements.JavaContext; public class GoogleFitModule extends ReactContextBaseJavaModule implements LifecycleEventListener { private static final String TAG = "RNGoogleFitness"; private static final String REACT_MODULE = "RNGoogleFit"; private ReactContext mReactContext; private GoogleSignInManager mGoogleSignInManager; public GoogleFitModule(ReactApplicationContext reactContext) { super(reactContext); mReactContext = reactContext; mGoogleSignInManager = new GoogleSignInManager(mReactContext); } @Override public String getName() { return REACT_MODULE; } @Override public void initialize() { super.initialize(); getReactApplicationContext().addLifecycleEventListener(this); } @Override public void onHostResume() { } @Override public void onHostPause() { } @Override public void onHostDestroy() { } @ReactMethod public void isGooglePlayServicesAvailable(final Promise promise) { promise.resolve(GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(getReactApplicationContext())); } @ReactMethod public void showGooglePlayServiceErrorDialog(int status, final Promise promise) { Dialog dialog = GoogleApiAvailability.getInstance().getErrorDialog(getCurrentActivity(), status, 0); if (dialog != null) { dialog.show(); promise.resolve(true); } else { promise.resolve(false); } } @ReactMethod public void requestPermissions(String fitnessOptionJsonStr, final Promise promise) { FitnessOptions fitnessOptions = null; try { fitnessOptions = (FitnessOptions) StatementFactory .fromJson(fitnessOptionJsonStr) .execute(new JavaContext(), null); } catch (Exception e) { Log.e(TAG, "Failed to create FitnessOptions", e); promise.reject(e); return; } if (!mGoogleSignInManager.requestPermissions(getCurrentActivity(), fitnessOptions, new GoogleSignInManager.ResultListener() { @Override public void onResult(int resultCode) { if (resultCode == Activity.RESULT_OK) { promise.resolve("SUCCESS"); } else if (resultCode == Activity.RESULT_CANCELED) { promise.resolve("CANCELED"); } } })) { promise.resolve("ALREADY_SIGNED_IN"); } } @ReactMethod public void hasPermissions(String fitnessOptionJsonStr, Promise promise) { if (GoogleSignIn.getLastSignedInAccount(mReactContext) == null) { promise.resolve(false); return; } try { FitnessOptions fitnessOptions = (FitnessOptions) StatementFactory .fromJson(fitnessOptionJsonStr) .execute(new JavaContext(), null); promise.resolve(GoogleSignIn.hasPermissions(getLastSignedInAccountSafely(), fitnessOptions)); } catch (Exception e) { Log.e(TAG, "Failed to create FitnessOptions", e); promise.reject(e); } } @ReactMethod public void disableFit(Promise promise) { try { Fitness .getConfigClient(mReactContext, getLastSignedInAccountSafely()) .disableFit() .continueWithTask(new Continuation<Void, Task<Void>>() { @Override public Task<Void> then(@NonNull Task<Void> task) throws Exception { GoogleSignInOptions options = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN).build(); return GoogleSignIn .getClient(mReactContext, options) .signOut(); } }) .addOnFailureListener(new SimpleFailureListener(promise)) .addOnSuccessListener(new SimpleSuccessListener(promise)); } catch (Exception e) { promise.reject(e); } } private HistoryClient getHistoryClient() { return Fitness.getHistoryClient(mReactContext, getLastSignedInAccountSafely()); } private GoogleSignInAccount getLastSignedInAccountSafely() { GoogleSignInAccount account = GoogleSignIn.getLastSignedInAccount(mReactContext); if (account == null) { throw new NullPointerException("No signed in google account. GoogleSignIn.getLastSignedInAccount() returned null."); } return account; } @ReactMethod public void history_insertData(String jsonStatement, final Promise promise) { try { DataSet dataSet = (DataSet) StatementFactory .fromJson(jsonStatement) .execute(new JavaContext(), null); getHistoryClient() .insertData(dataSet) .addOnFailureListener(new SimpleFailureListener(promise)) .addOnSuccessListener(new SimpleSuccessListener(promise)); } catch (Exception e) { Log.e(TAG, "Error in history_insertData()", e); promise.reject(e); } } @ReactMethod public void history_readData(String jsonStatement, final Promise promise) { try { DataReadRequest dataReadRequest = (DataReadRequest) StatementFactory .fromJson(jsonStatement) .execute(new JavaContext(), null); getHistoryClient() .readData(dataReadRequest) .addOnFailureListener(new SimpleFailureListener(promise)) .addOnSuccessListener(new OnSuccessListener<DataReadResponse>() { @Override public void onSuccess(DataReadResponse result) { WritableNativeArray dataSets = JSONEncoder.convertDataSets(result.getDataSets()); WritableNativeArray buckets = JSONEncoder.convertBuckets(result.getBuckets()); WritableNativeMap map = new WritableNativeMap(); map.putString("status", result.getStatus().toString()); map.putArray("dataSets", dataSets); map.putArray("buckets", buckets); promise.resolve(map); } }); } catch (Exception e) { Log.e(TAG, "Error in history_readData()", e); promise.reject(e); } } @ReactMethod public void history_updateData(String jsonStatement, final Promise promise) { try { DataUpdateRequest updateRequest = (DataUpdateRequest) StatementFactory .fromJson(jsonStatement) .execute(new JavaContext(), null); getHistoryClient() .updateData(updateRequest) .addOnFailureListener(new SimpleFailureListener(promise)) .addOnSuccessListener(new SimpleSuccessListener(promise)); } catch (Exception e) { Log.e(TAG, "Error in history_updateData()", e); promise.reject(e); } } @ReactMethod public void history_deleteData(String jsonStatement, final Promise promise) { try { DataDeleteRequest deleteRequest = (DataDeleteRequest) StatementFactory .fromJson(jsonStatement) .execute(new JavaContext(), null); getHistoryClient() .deleteData(deleteRequest) .addOnFailureListener(new SimpleFailureListener(promise)) .addOnSuccessListener(new SimpleSuccessListener(promise)); } catch (Exception e) { Log.e(TAG, "Error in history_deleteData()", e); promise.reject(e); } } @ReactMethod public void history_readDailyTotal(String jsonStatement, final Promise promise) { try { DataType dataType = (DataType) StatementFactory .fromJson(jsonStatement) .execute(new JavaContext(), null); getHistoryClient() .readDailyTotal(dataType) .addOnFailureListener(new SimpleFailureListener(promise)) .addOnSuccessListener(new OnSuccessListener<DataSet>() { @Override public void onSuccess(DataSet dataSet) { promise.resolve(JSONEncoder.convertDataSet(dataSet)); } }); } catch (Exception e) { Log.e(TAG, "Error in history_readDailyTotal()", e); promise.reject(e); } } @ReactMethod public void history_readDailyTotalFromLocalDevice(String jsonStatement, final Promise promise) { try { DataType dataType = (DataType) StatementFactory .fromJson(jsonStatement) .execute(new JavaContext(), null); getHistoryClient() .readDailyTotalFromLocalDevice(dataType) .addOnFailureListener(new SimpleFailureListener(promise)) .addOnSuccessListener(new OnSuccessListener<DataSet>() { @Override public void onSuccess(DataSet dataSet) { promise.resolve(JSONEncoder.convertDataSet(dataSet)); } }); } catch (Exception e) { Log.e(TAG, "Error in history_readDailyTotal()", e); promise.reject(e); } } private static class SimpleFailureListener implements OnFailureListener { private Promise mPromise; public SimpleFailureListener(Promise promise) { mPromise = promise; } @Override public void onFailure(@NonNull Exception e) { mPromise.reject(e); } } private static class SimpleSuccessListener implements OnSuccessListener { private Promise mPromise; public SimpleSuccessListener(Promise promise) { mPromise = promise; } @Override public void onSuccess(Object o) { mPromise.resolve(null); } } }