diff --git a/android/src/main/java/io/invertase/firebase/RNFirebaseModule.java b/android/src/main/java/io/invertase/firebase/RNFirebaseModule.java index 9a38c745..4ea94ab7 100644 --- a/android/src/main/java/io/invertase/firebase/RNFirebaseModule.java +++ b/android/src/main/java/io/invertase/firebase/RNFirebaseModule.java @@ -1,30 +1,30 @@ package io.invertase.firebase; -import android.util.Log; import android.app.Activity; import android.content.IntentSender; +import android.util.Log; -import java.util.Map; -import java.util.List; -import java.util.HashMap; -import java.util.ArrayList; - -// react -import com.facebook.react.bridge.Promise; -import com.facebook.react.bridge.Callback; import com.facebook.react.bridge.Arguments; -import com.facebook.react.bridge.ReadableMap; -import com.facebook.react.bridge.WritableMap; -import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.bridge.Callback; +import com.facebook.react.bridge.Promise; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; - -// play services +import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.bridge.WritableMap; import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.GoogleApiAvailability; import com.google.firebase.FirebaseApp; import com.google.firebase.FirebaseOptions; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +// react +// play services + @SuppressWarnings("WeakerAccess") public class RNFirebaseModule extends ReactContextBaseJavaModule { private static final String TAG = "RNFirebase"; @@ -103,7 +103,9 @@ public class RNFirebaseModule extends ReactContextBaseJavaModule { if (status != ConnectionResult.SUCCESS && gapi.isUserResolvableError(status)) { Activity activity = getCurrentActivity(); if (activity != null) { - gapi.getErrorDialog(activity, status, status).show(); + gapi + .getErrorDialog(activity, status, status) + .show(); } } } @@ -113,7 +115,9 @@ public class RNFirebaseModule extends ReactContextBaseJavaModule { */ @ReactMethod public void resolutionForPlayServices() { - int status = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(getReactApplicationContext()); + int status = GoogleApiAvailability + .getInstance() + .isGooglePlayServicesAvailable(getReactApplicationContext()); ConnectionResult connectionResult = new ConnectionResult(status); if (!connectionResult.isSuccess() && connectionResult.hasResolution()) { diff --git a/android/src/main/java/io/invertase/firebase/RNFirebasePackage.java b/android/src/main/java/io/invertase/firebase/RNFirebasePackage.java index 4c4ea50c..04d656f0 100644 --- a/android/src/main/java/io/invertase/firebase/RNFirebasePackage.java +++ b/android/src/main/java/io/invertase/firebase/RNFirebasePackage.java @@ -8,9 +8,9 @@ import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.uimanager.UIManagerModule; import com.facebook.react.uimanager.ViewManager; -import java.util.List; import java.util.ArrayList; import java.util.Collections; +import java.util.List; @SuppressWarnings("unused") public class RNFirebasePackage implements ReactPackage { diff --git a/android/src/main/java/io/invertase/firebase/Utils.java b/android/src/main/java/io/invertase/firebase/Utils.java index 0d8eba07..852774fa 100644 --- a/android/src/main/java/io/invertase/firebase/Utils.java +++ b/android/src/main/java/io/invertase/firebase/Utils.java @@ -1,9 +1,7 @@ package io.invertase.firebase; -import android.annotation.SuppressLint; import android.app.ActivityManager; import android.content.Context; -import android.os.AsyncTask; import android.util.Log; import com.facebook.react.bridge.Arguments; @@ -48,7 +46,9 @@ public class Utils { if (value == null) { map.putNull(key); } else { - String type = value.getClass().getName(); + String type = value + .getClass() + .getName(); switch (type) { case "java.lang.Boolean": map.putBoolean(key, (Boolean) value); @@ -159,7 +159,9 @@ public class Utils { } public static int getResId(Context ctx, String resName) { - int resourceId = ctx.getResources().getIdentifier(resName, "string", ctx.getPackageName()); + int resourceId = ctx + .getResources() + .getIdentifier(resName, "string", ctx.getPackageName()); if (resourceId == 0) { Log.e(TAG, "resource " + resName + " could not be found"); } diff --git a/android/src/main/java/io/invertase/firebase/admob/RNFirebaseAdMob.java b/android/src/main/java/io/invertase/firebase/admob/RNFirebaseAdMob.java index 0606b7f9..a8d2ec6d 100644 --- a/android/src/main/java/io/invertase/firebase/admob/RNFirebaseAdMob.java +++ b/android/src/main/java/io/invertase/firebase/admob/RNFirebaseAdMob.java @@ -18,6 +18,13 @@ import java.util.Map; public class RNFirebaseAdMob extends ReactContextBaseJavaModule { private static final String TAG = "RNFirebaseAdMob"; + private HashMap interstitials = new HashMap<>(); + private HashMap rewardedVideos = new HashMap<>(); + + public RNFirebaseAdMob(ReactApplicationContext reactContext) { + super(reactContext); + Log.d(TAG, "New instance"); + } ReactApplicationContext getContext() { return getReactApplicationContext(); @@ -27,14 +34,6 @@ public class RNFirebaseAdMob extends ReactContextBaseJavaModule { return getCurrentActivity(); } - private HashMap interstitials = new HashMap<>(); - private HashMap rewardedVideos = new HashMap<>(); - - public RNFirebaseAdMob(ReactApplicationContext reactContext) { - super(reactContext); - Log.d(TAG, "New instance"); - } - @Override public String getName() { return TAG; @@ -53,7 +52,9 @@ public class RNFirebaseAdMob extends ReactContextBaseJavaModule { @ReactMethod public void interstitialLoadAd(String adUnit, ReadableMap request) { RNFirebaseAdmobInterstitial interstitial = getOrCreateInterstitial(adUnit); - interstitial.loadAd(RNFirebaseAdMobUtils.buildRequest(request).build()); + interstitial.loadAd(RNFirebaseAdMobUtils + .buildRequest(request) + .build()); } @ReactMethod @@ -65,7 +66,9 @@ public class RNFirebaseAdMob extends ReactContextBaseJavaModule { @ReactMethod public void rewardedVideoLoadAd(String adUnit, ReadableMap request) { RNFirebaseAdMobRewardedVideo rewardedVideo = getOrCreateRewardedVideo(adUnit); - rewardedVideo.loadAd(RNFirebaseAdMobUtils.buildRequest(request).build()); + rewardedVideo.loadAd(RNFirebaseAdMobUtils + .buildRequest(request) + .build()); } @ReactMethod @@ -75,7 +78,6 @@ public class RNFirebaseAdMob extends ReactContextBaseJavaModule { } /** - * * @param adUnit * @return */ @@ -89,7 +91,6 @@ public class RNFirebaseAdMob extends ReactContextBaseJavaModule { } /** - * * @param adUnit * @return */ diff --git a/android/src/main/java/io/invertase/firebase/admob/RNFirebaseAdMobBanner.java b/android/src/main/java/io/invertase/firebase/admob/RNFirebaseAdMobBanner.java index 8aa2a643..445cc688 100644 --- a/android/src/main/java/io/invertase/firebase/admob/RNFirebaseAdMobBanner.java +++ b/android/src/main/java/io/invertase/firebase/admob/RNFirebaseAdMobBanner.java @@ -23,38 +23,15 @@ public class RNFirebaseAdMobBanner extends SimpleViewManager { public static final String REACT_CLASS = "RNFirebaseAdMobBanner"; public static final String BANNER_EVENT = "onBannerEvent"; - - public enum Events { - EVENT_AD_SIZE_CHANGE("onSizeChange"), - EVENT_AD_LOADED("onAdLoaded"), - EVENT_AD_FAILED_TO_LOAD("onAdFailedToLoad"), - EVENT_AD_OPENED("onAdOpened"), - EVENT_AD_CLOSED("onAdClosed"), - EVENT_AD_LEFT_APPLICATION("onAdLeftApplication"); - - private final String event; - - Events(final String name) { - event = name; - } - - @Override - public String toString() { - return event; - } - } - private ThemedReactContext context; private ReactViewGroup viewGroup; private RCTEventEmitter emitter; private Boolean requested = false; - // Internal prop values private AdRequest.Builder request; private AdSize size; private String unitId; - @Override public String getName() { return REACT_CLASS; @@ -197,15 +174,22 @@ public class RNFirebaseAdMobBanner extends SimpleViewManager { int left = adView.getLeft(); int top = adView.getTop(); - int width = adView.getAdSize().getWidthInPixels(context); - int height = adView.getAdSize().getHeightInPixels(context); + int width = adView + .getAdSize() + .getWidthInPixels(context); + int height = adView + .getAdSize() + .getHeightInPixels(context); adView.measure(width, height); adView.layout(left, top, left + width, top + height); WritableMap payload = Arguments.createMap(); - payload.putBoolean(RNFirebaseAdMobNativeExpress.Events.EVENT_AD_VIDEO_CONTENT.toString(), false); + payload.putBoolean( + RNFirebaseAdMobNativeExpress.Events.EVENT_AD_VIDEO_CONTENT.toString(), + false + ); payload.putInt("width", width); payload.putInt("height", height); @@ -251,4 +235,24 @@ public class RNFirebaseAdMobBanner extends SimpleViewManager { emitter.receiveEvent(viewGroup.getId(), BANNER_EVENT, event); } + + public enum Events { + EVENT_AD_SIZE_CHANGE("onSizeChange"), + EVENT_AD_LOADED("onAdLoaded"), + EVENT_AD_FAILED_TO_LOAD("onAdFailedToLoad"), + EVENT_AD_OPENED("onAdOpened"), + EVENT_AD_CLOSED("onAdClosed"), + EVENT_AD_LEFT_APPLICATION("onAdLeftApplication"); + + private final String event; + + Events(final String name) { + event = name; + } + + @Override + public String toString() { + return event; + } + } } diff --git a/android/src/main/java/io/invertase/firebase/admob/RNFirebaseAdMobNativeExpress.java b/android/src/main/java/io/invertase/firebase/admob/RNFirebaseAdMobNativeExpress.java index 583efda2..3615e7ad 100644 --- a/android/src/main/java/io/invertase/firebase/admob/RNFirebaseAdMobNativeExpress.java +++ b/android/src/main/java/io/invertase/firebase/admob/RNFirebaseAdMobNativeExpress.java @@ -25,38 +25,10 @@ public class RNFirebaseAdMobNativeExpress extends SimpleViewManager() { @Override public void onSuccess(AuthResult authResult) { @@ -239,21 +238,38 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule { * @param promise */ @ReactMethod - public void createUserWithEmailAndPassword(String appName, final String email, final String password, final Promise promise) { + public void createUserWithEmailAndPassword( + String appName, + final String email, + final String password, + final Promise promise + ) { createUserWithEmailAndPassword(appName, email, password, promise, false); } @ReactMethod - public void createUserAndRetrieveDataWithEmailAndPassword(String appName, final String email, final String password, final Promise promise) { + public void createUserAndRetrieveDataWithEmailAndPassword( + String appName, + final String email, + final String password, + final Promise promise + ) { createUserWithEmailAndPassword(appName, email, password, promise, true); } - private void createUserWithEmailAndPassword(String appName, final String email, final String password, final Promise promise, final boolean withData) { + private void createUserWithEmailAndPassword( + String appName, + final String email, + final String password, + final Promise promise, + final boolean withData + ) { Log.d(TAG, "createUserWithEmailAndPassword"); FirebaseApp firebaseApp = FirebaseApp.getInstance(appName); FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp); - firebaseAuth.createUserWithEmailAndPassword(email, password) + firebaseAuth + .createUserWithEmailAndPassword(email, password) .addOnSuccessListener(new OnSuccessListener() { @Override public void onSuccess(AuthResult authResult) { @@ -282,21 +298,38 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule { * @param promise */ @ReactMethod - public void signInWithEmailAndPassword(String appName, final String email, final String password, final Promise promise) { + public void signInWithEmailAndPassword( + String appName, + final String email, + final String password, + final Promise promise + ) { signInWithEmailAndPassword(appName, email, password, promise, false); } @ReactMethod - public void signInAndRetrieveDataWithEmailAndPassword(String appName, final String email, final String password, final Promise promise) { + public void signInAndRetrieveDataWithEmailAndPassword( + String appName, + final String email, + final String password, + final Promise promise + ) { signInWithEmailAndPassword(appName, email, password, promise, true); } - private void signInWithEmailAndPassword(String appName, final String email, final String password, final Promise promise, final boolean withData) { + private void signInWithEmailAndPassword( + String appName, + final String email, + final String password, + final Promise promise, + final boolean withData + ) { Log.d(TAG, "signInWithEmailAndPassword"); FirebaseApp firebaseApp = FirebaseApp.getInstance(appName); FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp); - firebaseAuth.signInWithEmailAndPassword(email, password) + firebaseAuth + .signInWithEmailAndPassword(email, password) .addOnSuccessListener(new OnSuccessListener() { @Override public void onSuccess(AuthResult authResult) { @@ -326,12 +359,18 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule { * @param promise */ @ReactMethod - private void signInWithEmailLink(String appName, final String email, final String emailLink, final Promise promise) { + private void signInWithEmailLink( + String appName, + final String email, + final String emailLink, + final Promise promise + ) { Log.d(TAG, "signInWithEmailLink"); FirebaseApp firebaseApp = FirebaseApp.getInstance(appName); FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp); - firebaseAuth.signInWithEmailLink(email, emailLink) + firebaseAuth + .signInWithEmailLink(email, emailLink) .addOnSuccessListener(new OnSuccessListener() { @Override public void onSuccess(AuthResult authResult) { @@ -356,16 +395,26 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule { @ReactMethod - public void signInAndRetrieveDataWithCustomToken(String appName, final String token, final Promise promise) { + public void signInAndRetrieveDataWithCustomToken( + String appName, + final String token, + final Promise promise + ) { signInWithCustomToken(appName, token, promise, true); } - private void signInWithCustomToken(String appName, final String token, final Promise promise, final boolean withData) { + private void signInWithCustomToken( + String appName, + final String token, + final Promise promise, + final boolean withData + ) { Log.d(TAG, "signInWithCustomToken"); FirebaseApp firebaseApp = FirebaseApp.getInstance(appName); FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp); - firebaseAuth.signInWithCustomToken(token) + firebaseAuth + .signInWithCustomToken(token) .addOnSuccessListener(new OnSuccessListener() { @Override public void onSuccess(AuthResult authResult) { @@ -393,7 +442,12 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule { * @param promise */ @ReactMethod - public void sendPasswordResetEmail(String appName, final String email, ReadableMap actionCodeSettings, final Promise promise) { + public void sendPasswordResetEmail( + String appName, + final String email, + ReadableMap actionCodeSettings, + final Promise promise + ) { Log.d(TAG, "sendPasswordResetEmail"); FirebaseApp firebaseApp = FirebaseApp.getInstance(appName); FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp); @@ -413,10 +467,14 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule { }; if (actionCodeSettings == null) { - firebaseAuth.sendPasswordResetEmail(email).addOnCompleteListener(listener); + firebaseAuth + .sendPasswordResetEmail(email) + .addOnCompleteListener(listener); } else { ActionCodeSettings settings = buildActionCodeSettings(actionCodeSettings); - firebaseAuth.sendPasswordResetEmail(email, settings).addOnCompleteListener(listener); + firebaseAuth + .sendPasswordResetEmail(email, settings) + .addOnCompleteListener(listener); } } @@ -427,7 +485,12 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule { * @param promise */ @ReactMethod - public void sendSignInLinkToEmail(String appName, String email, ReadableMap actionCodeSettings, final Promise promise) { + public void sendSignInLinkToEmail( + String appName, + String email, + ReadableMap actionCodeSettings, + final Promise promise + ) { Log.d(TAG, "sendSignInLinkToEmail"); FirebaseApp firebaseApp = FirebaseApp.getInstance(appName); FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp); @@ -448,7 +511,9 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule { ActionCodeSettings settings = buildActionCodeSettings(actionCodeSettings); - firebaseAuth.sendSignInLinkToEmail(email, settings).addOnCompleteListener(listener); + firebaseAuth + .sendSignInLinkToEmail(email, settings) + .addOnCompleteListener(listener); } @@ -470,7 +535,8 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule { FirebaseUser user = firebaseAuth.getCurrentUser(); Log.d(TAG, "delete"); if (user != null) { - user.delete() + user + .delete() .addOnCompleteListener(new OnCompleteListener() { @Override public void onComplete(@NonNull Task task) { @@ -507,7 +573,8 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule { promiseNoUser(promise, false); Log.e(TAG, "reload:failure:noCurrentUser"); } else { - user.reload() + user + .reload() .addOnCompleteListener(new OnCompleteListener() { @Override public void onComplete(@NonNull Task task) { @@ -530,7 +597,11 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule { * @param promise */ @ReactMethod - public void sendEmailVerification(String appName, ReadableMap actionCodeSettings, final Promise promise) { + public void sendEmailVerification( + String appName, + ReadableMap actionCodeSettings, + final Promise promise + ) { FirebaseApp firebaseApp = FirebaseApp.getInstance(appName); final FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp); @@ -556,10 +627,14 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule { }; if (actionCodeSettings == null) { - user.sendEmailVerification().addOnCompleteListener(listener); + user + .sendEmailVerification() + .addOnCompleteListener(listener); } else { ActionCodeSettings settings = buildActionCodeSettings(actionCodeSettings); - user.sendEmailVerification(settings).addOnCompleteListener(listener); + user + .sendEmailVerification(settings) + .addOnCompleteListener(listener); } } } @@ -582,7 +657,8 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule { promiseNoUser(promise, false); Log.e(TAG, "updateEmail:failure:noCurrentUser"); } else { - user.updateEmail(email) + user + .updateEmail(email) .addOnCompleteListener(new OnCompleteListener() { @Override public void onComplete(@NonNull Task task) { @@ -617,7 +693,8 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule { promiseNoUser(promise, false); Log.e(TAG, "updatePassword:failure:noCurrentUser"); } else { - user.updatePassword(password) + user + .updatePassword(password) .addOnCompleteListener(new OnCompleteListener() { @Override public void onComplete(@NonNull Task task) { @@ -666,7 +743,8 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule { UserProfileChangeRequest profileUpdates = profileBuilder.build(); - user.updateProfile(profileUpdates) + user + .updateProfile(profileUpdates) .addOnCompleteListener(new OnCompleteListener() { @Override public void onComplete(@NonNull Task task) { @@ -684,26 +762,49 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule { } @ReactMethod - public void signInWithCredential(String appName, String provider, String authToken, String authSecret, final Promise promise) { + public void signInWithCredential( + String appName, + String provider, + String authToken, + String authSecret, + final Promise promise + ) { signInWithCredential(appName, provider, authToken, authSecret, promise, false); } @ReactMethod - public void signInAndRetrieveDataWithCredential(String appName, String provider, String authToken, String authSecret, final Promise promise) { + public void signInAndRetrieveDataWithCredential( + String appName, + String provider, + String authToken, + String authSecret, + final Promise promise + ) { signInWithCredential(appName, provider, authToken, authSecret, promise, true); } - private void signInWithCredential(String appName, String provider, String authToken, String authSecret, final Promise promise, final boolean withData) { + private void signInWithCredential( + String appName, + String provider, + String authToken, + String authSecret, + final Promise promise, + final boolean withData + ) { FirebaseApp firebaseApp = FirebaseApp.getInstance(appName); FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp); AuthCredential credential = getCredentialForProvider(provider, authToken, authSecret); if (credential == null) { - promise.reject("auth/invalid-credential", "The supplied auth credential is malformed, has expired or is not currently supported."); + promise.reject( + "auth/invalid-credential", + "The supplied auth credential is malformed, has expired or is not currently supported." + ); } else { Log.d(TAG, "signInWithCredential"); - firebaseAuth.signInWithCredential(credential) + firebaseAuth + .signInWithCredential(credential) .addOnCompleteListener(new OnCompleteListener() { @Override public void onComplete(@NonNull Task task) { @@ -712,7 +813,9 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule { if (withData) { promiseWithAuthResult(task.getResult(), promise); } else { - promiseWithUser(task.getResult().getUser(), promise); + promiseWithUser(task + .getResult() + .getUser(), promise); } } else { Exception exception = task.getException(); @@ -731,7 +834,12 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule { * @param phoneNumber */ @ReactMethod - public void signInWithPhoneNumber(String appName, final String phoneNumber, final boolean forceResend, final Promise promise) { + public void signInWithPhoneNumber( + String appName, + final String phoneNumber, + final boolean forceResend, + final Promise promise + ) { Log.d(TAG, "signInWithPhoneNumber"); FirebaseApp firebaseApp = FirebaseApp.getInstance(appName); final FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp); @@ -752,13 +860,17 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule { @Override public void onVerificationCompleted(final PhoneAuthCredential phoneAuthCredential) { // User has been automatically verified, log them in - firebaseAuth.signInWithCredential(phoneAuthCredential) + firebaseAuth + .signInWithCredential(phoneAuthCredential) .addOnCompleteListener(new OnCompleteListener() { @Override public void onComplete(@NonNull Task task) { if (task.isSuccessful()) { // onAuthStateChanged will pick up the user change - Log.d(TAG, "signInWithPhoneNumber:autoVerified:signInWithCredential:onComplete:success"); + Log.d( + TAG, + "signInWithPhoneNumber:autoVerified:signInWithCredential:onComplete:success" + ); // To ensure that there is no hanging promise, we resolve it with a null verificationId // as calling ConfirmationResult.confirm(code) is invalid in this case anyway if (!promiseResolved) { @@ -770,7 +882,11 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule { // With phone auth, the credential will only every be rejected if the user // account linked to the phone number has been disabled Exception exception = task.getException(); - Log.e(TAG, "signInWithPhoneNumber:autoVerified:signInWithCredential:onComplete:failure", exception); + Log.e( + TAG, + "signInWithPhoneNumber:autoVerified:signInWithCredential:onComplete:failure", + exception + ); // In the scenario where an SMS code has been sent, we have no way to report // back to the front-end that as the promise has already been used if (!promiseResolved) { @@ -791,7 +907,10 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule { } @Override - public void onCodeSent(String verificationId, PhoneAuthProvider.ForceResendingToken forceResendingToken) { + public void onCodeSent( + String verificationId, + PhoneAuthProvider.ForceResendingToken forceResendingToken + ) { // TODO: This isn't being saved anywhere if the activity gets restarted when going to the SMS app mVerificationId = verificationId; mForceResendingToken = forceResendingToken; @@ -810,7 +929,8 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule { if (activity != null) { if (forceResend && mForceResendingToken != null) { - PhoneAuthProvider.getInstance(firebaseAuth) + PhoneAuthProvider + .getInstance(firebaseAuth) .verifyPhoneNumber( phoneNumber, 60, @@ -820,7 +940,8 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule { mForceResendingToken ); } else { - PhoneAuthProvider.getInstance(firebaseAuth) + PhoneAuthProvider + .getInstance(firebaseAuth) .verifyPhoneNumber( phoneNumber, 60, @@ -833,22 +954,39 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule { } @ReactMethod - public void _confirmVerificationCode(String appName, final String verificationCode, final Promise promise) { + public void _confirmVerificationCode( + String appName, + final String verificationCode, + final Promise promise + ) { FirebaseApp firebaseApp = FirebaseApp.getInstance(appName); FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp); - PhoneAuthCredential credential = PhoneAuthProvider.getCredential(mVerificationId, verificationCode); + PhoneAuthCredential credential = PhoneAuthProvider.getCredential( + mVerificationId, + verificationCode + ); - firebaseAuth.signInWithCredential(credential) + firebaseAuth + .signInWithCredential(credential) .addOnCompleteListener(new OnCompleteListener() { @Override public void onComplete(@NonNull Task task) { if (task.isSuccessful()) { - Log.d(TAG, "_confirmVerificationCode:signInWithCredential:onComplete:success"); - promiseWithUser(task.getResult().getUser(), promise); + Log.d( + TAG, + "_confirmVerificationCode:signInWithCredential:onComplete:success" + ); + promiseWithUser(task + .getResult() + .getUser(), promise); } else { Exception exception = task.getException(); - Log.e(TAG, "_confirmVerificationCode:signInWithCredential:onComplete:failure", exception); + Log.e( + TAG, + "_confirmVerificationCode:signInWithCredential:onComplete:failure", + exception + ); promiseRejectAuthException(promise, exception); } } @@ -863,7 +1001,13 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule { * @param timeout */ @ReactMethod - public void verifyPhoneNumber(final String appName, final String phoneNumber, final String requestKey, final int timeout, final boolean forceResend) { + public void verifyPhoneNumber( + final String appName, + final String phoneNumber, + final String requestKey, + final int timeout, + final boolean forceResend + ) { FirebaseApp firebaseApp = FirebaseApp.getInstance(appName); final FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp); final Activity activity = mReactContext.getCurrentActivity(); @@ -918,7 +1062,10 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule { } @Override - public void onCodeSent(String verificationId, PhoneAuthProvider.ForceResendingToken forceResendingToken) { + public void onCodeSent( + String verificationId, + PhoneAuthProvider.ForceResendingToken forceResendingToken + ) { Log.d(TAG, "verifyPhoneNumber:verification:onCodeSent"); mForceResendingToken = forceResendingToken; WritableMap state = Arguments.createMap(); @@ -953,7 +1100,8 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule { if (activity != null) { if (forceResend && mForceResendingToken != null) { - PhoneAuthProvider.getInstance(firebaseAuth) + PhoneAuthProvider + .getInstance(firebaseAuth) .verifyPhoneNumber( phoneNumber, timeout, @@ -963,7 +1111,8 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule { mForceResendingToken ); } else { - PhoneAuthProvider.getInstance(firebaseAuth) + PhoneAuthProvider + .getInstance(firebaseAuth) .verifyPhoneNumber( phoneNumber, timeout, @@ -983,13 +1132,19 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule { * @param promise */ @ReactMethod - public void confirmPasswordReset(String appName, String code, String newPassword, final Promise promise) { + public void confirmPasswordReset( + String appName, + String code, + String newPassword, + final Promise promise + ) { Log.d(TAG, "confirmPasswordReset"); FirebaseApp firebaseApp = FirebaseApp.getInstance(appName); FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp); - firebaseAuth.confirmPasswordReset(code, newPassword) + firebaseAuth + .confirmPasswordReset(code, newPassword) .addOnCompleteListener(new OnCompleteListener() { @Override public void onComplete(@NonNull Task task) { @@ -1018,19 +1173,21 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule { FirebaseApp firebaseApp = FirebaseApp.getInstance(appName); FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp); - firebaseAuth.applyActionCode(code).addOnCompleteListener(new OnCompleteListener() { - @Override - public void onComplete(@NonNull Task task) { - if (task.isSuccessful()) { - Log.d(TAG, "applyActionCode:onComplete:success"); - promiseNoUser(promise, false); - } else { - Exception exception = task.getException(); - Log.e(TAG, "applyActionCode:onComplete:failure", exception); - promiseRejectAuthException(promise, exception); + firebaseAuth + .applyActionCode(code) + .addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + Log.d(TAG, "applyActionCode:onComplete:success"); + promiseNoUser(promise, false); + } else { + Exception exception = task.getException(); + Log.e(TAG, "applyActionCode:onComplete:failure", exception); + promiseRejectAuthException(promise, exception); + } } - } - }); + }); } /** @@ -1044,51 +1201,53 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule { FirebaseApp firebaseApp = FirebaseApp.getInstance(appName); FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp); - firebaseAuth.checkActionCode(code).addOnCompleteListener(new OnCompleteListener() { - @Override - public void onComplete(@NonNull Task task) { - if (task.isSuccessful()) { - Log.d(TAG, "checkActionCode:onComplete:success"); - ActionCodeResult result = task.getResult(); + firebaseAuth + .checkActionCode(code) + .addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + Log.d(TAG, "checkActionCode:onComplete:success"); + ActionCodeResult result = task.getResult(); - WritableMap writableMap = Arguments.createMap(); - WritableMap dataMap = Arguments.createMap(); + WritableMap writableMap = Arguments.createMap(); + WritableMap dataMap = Arguments.createMap(); - dataMap.putString("email", result.getData(ActionCodeResult.EMAIL)); - dataMap.putString("fromEmail", result.getData(ActionCodeResult.FROM_EMAIL)); + dataMap.putString("email", result.getData(ActionCodeResult.EMAIL)); + dataMap.putString("fromEmail", result.getData(ActionCodeResult.FROM_EMAIL)); - writableMap.putMap("data", dataMap); + writableMap.putMap("data", dataMap); - String actionType = "UNKNOWN"; + String actionType = "UNKNOWN"; - switch (result.getOperation()) { - case ActionCodeResult.ERROR: - actionType = "ERROR"; - break; - case ActionCodeResult.VERIFY_EMAIL: - actionType = "VERIFY_EMAIL"; - break; - case ActionCodeResult.RECOVER_EMAIL: - actionType = "RECOVER_EMAIL"; - break; - case ActionCodeResult.PASSWORD_RESET: - actionType = "PASSWORD_RESET"; - break; - case ActionCodeResult.SIGN_IN_WITH_EMAIL_LINK: - actionType = "EMAIL_SIGNIN"; - break; + switch (result.getOperation()) { + case ActionCodeResult.ERROR: + actionType = "ERROR"; + break; + case ActionCodeResult.VERIFY_EMAIL: + actionType = "VERIFY_EMAIL"; + break; + case ActionCodeResult.RECOVER_EMAIL: + actionType = "RECOVER_EMAIL"; + break; + case ActionCodeResult.PASSWORD_RESET: + actionType = "PASSWORD_RESET"; + break; + case ActionCodeResult.SIGN_IN_WITH_EMAIL_LINK: + actionType = "EMAIL_SIGNIN"; + break; + } + + writableMap.putString("actionType", actionType); + + promise.resolve(writableMap); + } else { + Exception exception = task.getException(); + Log.e(TAG, "checkActionCode:onComplete:failure", exception); + promiseRejectAuthException(promise, exception); } - - writableMap.putString("actionType", actionType); - - promise.resolve(writableMap); - } else { - Exception exception = task.getException(); - Log.e(TAG, "checkActionCode:onComplete:failure", exception); - promiseRejectAuthException(promise, exception); } - } - }); + }); } /** @@ -1100,29 +1259,52 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule { * @param promise */ @ReactMethod - public void linkWithCredential(String appName, String provider, String authToken, String authSecret, final Promise promise) { + public void linkWithCredential( + String appName, + String provider, + String authToken, + String authSecret, + final Promise promise + ) { link(appName, provider, authToken, authSecret, promise, false); } @ReactMethod - public void linkAndRetrieveDataWithCredential(String appName, String provider, String authToken, String authSecret, final Promise promise) { + public void linkAndRetrieveDataWithCredential( + String appName, + String provider, + String authToken, + String authSecret, + final Promise promise + ) { link(appName, provider, authToken, authSecret, promise, true); } - private void link(String appName, String provider, String authToken, String authSecret, final Promise promise, final boolean withData) { + private void link( + String appName, + String provider, + String authToken, + String authSecret, + final Promise promise, + final boolean withData + ) { FirebaseApp firebaseApp = FirebaseApp.getInstance(appName); FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp); AuthCredential credential = getCredentialForProvider(provider, authToken, authSecret); if (credential == null) { - promise.reject("auth/invalid-credential", "The supplied auth credential is malformed, has expired or is not currently supported."); + promise.reject( + "auth/invalid-credential", + "The supplied auth credential is malformed, has expired or is not currently supported." + ); } else { FirebaseUser user = firebaseAuth.getCurrentUser(); Log.d(TAG, "link"); if (user != null) { - user.linkWithCredential(credential) + user + .linkWithCredential(credential) .addOnCompleteListener(new OnCompleteListener() { @Override public void onComplete(@NonNull Task task) { @@ -1131,7 +1313,9 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule { if (withData) { promiseWithAuthResult(task.getResult(), promise); } else { - promiseWithUser(task.getResult().getUser(), promise); + promiseWithUser(task + .getResult() + .getUser(), promise); } } else { Exception exception = task.getException(); @@ -1154,13 +1338,16 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule { Log.d(TAG, "unlink"); if (user != null) { - user.unlink(providerId) + user + .unlink(providerId) .addOnCompleteListener(new OnCompleteListener() { @Override public void onComplete(@NonNull Task task) { if (task.isSuccessful()) { Log.d(TAG, "unlink:onComplete:success"); - promiseWithUser(task.getResult().getUser(), promise); + promiseWithUser(task + .getResult() + .getUser(), promise); } else { Exception exception = task.getException(); Log.e(TAG, "unlink:onComplete:failure", exception); @@ -1174,29 +1361,52 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule { } @ReactMethod - public void reauthenticateWithCredential(String appName, String provider, String authToken, String authSecret, final Promise promise) { + public void reauthenticateWithCredential( + String appName, + String provider, + String authToken, + String authSecret, + final Promise promise + ) { reauthenticate(appName, provider, authToken, authSecret, promise, false); } @ReactMethod - public void reauthenticateAndRetrieveDataWithCredential(String appName, String provider, String authToken, String authSecret, final Promise promise) { + public void reauthenticateAndRetrieveDataWithCredential( + String appName, + String provider, + String authToken, + String authSecret, + final Promise promise + ) { reauthenticate(appName, provider, authToken, authSecret, promise, true); } - private void reauthenticate(String appName, String provider, String authToken, String authSecret, final Promise promise, final boolean withData) { + private void reauthenticate( + String appName, + String provider, + String authToken, + String authSecret, + final Promise promise, + final boolean withData + ) { FirebaseApp firebaseApp = FirebaseApp.getInstance(appName); final FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp); AuthCredential credential = getCredentialForProvider(provider, authToken, authSecret); if (credential == null) { - promise.reject("auth/invalid-credential", "The supplied auth credential is malformed, has expired or is not currently supported."); + promise.reject( + "auth/invalid-credential", + "The supplied auth credential is malformed, has expired or is not currently supported." + ); } else { FirebaseUser user = firebaseAuth.getCurrentUser(); Log.d(TAG, "reauthenticate"); if (user != null) { - user.reauthenticateAndRetrieveData(credential) + user + .reauthenticateAndRetrieveData(credential) .addOnCompleteListener(new OnCompleteListener() { @Override public void onComplete(@NonNull Task task) { @@ -1205,7 +1415,9 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule { if (withData) { promiseWithAuthResult(task.getResult(), promise); } else { - promiseWithUser(task.getResult().getUser(), promise); + promiseWithUser(task + .getResult() + .getUser(), promise); } } else { Exception exception = task.getException(); @@ -1223,7 +1435,11 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule { /** * Returns an instance of AuthCredential for the specified provider */ - private AuthCredential getCredentialForProvider(String provider, String authToken, String authSecret) { + private AuthCredential getCredentialForProvider( + String provider, + String authToken, + String authSecret + ) { switch (provider) { case "facebook.com": return FacebookAuthProvider.getCredential(authToken); @@ -1268,13 +1484,16 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule { Log.d(TAG, "getToken/getIdToken"); if (user != null) { - user.getIdToken(forceRefresh) + user + .getIdToken(forceRefresh) .addOnCompleteListener(new OnCompleteListener() { @Override public void onComplete(@NonNull Task task) { if (task.isSuccessful()) { Log.d(TAG, "getToken:onComplete:success"); - promise.resolve(task.getResult().getToken()); + promise.resolve(task + .getResult() + .getToken()); } else { Exception exception = task.getException(); Log.e(TAG, "getToken:onComplete:failure", exception); @@ -1294,13 +1513,16 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule { Log.d(TAG, "fetchProvidersForEmail"); - firebaseAuth.fetchSignInMethodsForEmail(email) + firebaseAuth + .fetchSignInMethodsForEmail(email) .addOnCompleteListener(new OnCompleteListener() { @Override public void onComplete(@NonNull Task task) { if (task.isSuccessful()) { Log.d(TAG, "fetchProvidersForEmail:onComplete:success"); - List providers = task.getResult().getSignInMethods(); + List providers = task + .getResult() + .getSignInMethods(); WritableArray array = Arguments.createArray(); if (providers != null) { @@ -1342,19 +1564,21 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule { FirebaseApp firebaseApp = FirebaseApp.getInstance(appName); FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp); - firebaseAuth.verifyPasswordResetCode(code).addOnCompleteListener(new OnCompleteListener() { - @Override - public void onComplete(@NonNull Task task) { - if (task.isSuccessful()) { - Log.d(TAG, "verifyPasswordResetCode:onComplete:success"); - promise.resolve(task.getResult()); - } else { - Exception exception = task.getException(); - Log.e(TAG, "verifyPasswordResetCode:onComplete:failure", exception); - promiseRejectAuthException(promise, exception); + firebaseAuth + .verifyPasswordResetCode(code) + .addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + Log.d(TAG, "verifyPasswordResetCode:onComplete:success"); + promise.resolve(task.getResult()); + } else { + Exception exception = task.getException(); + Log.e(TAG, "verifyPasswordResetCode:onComplete:failure", exception); + promiseRejectAuthException(promise, exception); + } } - } - }); + }); } /* ------------------ @@ -1402,15 +1626,42 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule { WritableMap authResultMap = Arguments.createMap(); if (authResult.getAdditionalUserInfo() != null) { WritableMap additionalUserInfoMap = Arguments.createMap(); - additionalUserInfoMap.putBoolean("isNewUser", authResult.getAdditionalUserInfo().isNewUser()); - if (authResult.getAdditionalUserInfo().getProfile() != null) { - Utils.mapPutValue("profile", authResult.getAdditionalUserInfo().getProfile(), additionalUserInfoMap); + additionalUserInfoMap.putBoolean( + "isNewUser", + authResult + .getAdditionalUserInfo() + .isNewUser() + ); + if (authResult + .getAdditionalUserInfo() + .getProfile() != null) { + Utils.mapPutValue( + "profile", + authResult + .getAdditionalUserInfo() + .getProfile(), + additionalUserInfoMap + ); } - if (authResult.getAdditionalUserInfo().getProviderId() != null) { - additionalUserInfoMap.putString("providerId", authResult.getAdditionalUserInfo().getProviderId()); + if (authResult + .getAdditionalUserInfo() + .getProviderId() != null) { + additionalUserInfoMap.putString( + "providerId", + authResult + .getAdditionalUserInfo() + .getProviderId() + ); } - if (authResult.getAdditionalUserInfo().getUsername() != null) { - additionalUserInfoMap.putString("username", authResult.getAdditionalUserInfo().getUsername()); + if (authResult + .getAdditionalUserInfo() + .getUsername() != null) { + additionalUserInfoMap.putString( + "username", + authResult + .getAdditionalUserInfo() + .getUsername() + ); } authResultMap.putMap("additionalUserInfo", additionalUserInfoMap); } @@ -1449,9 +1700,13 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule { error.putString("nativeErrorCode", code); message = authException.getMessage(); } catch (Exception e) { - Matcher matcher = Pattern.compile("([A-Z]*_[A-Z]*)").matcher(message); + Matcher matcher = Pattern + .compile("([A-Z]*_[A-Z]*)") + .matcher(message); if (matcher.find()) { - code = matcher.group(1).trim(); + code = matcher + .group(1) + .trim(); switch (code) { case "INVALID_CUSTOM_TOKEN": message = "The custom token format is incorrect. Please check the documentation."; @@ -1514,7 +1769,10 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule { message = invalidEmail; } - code = "auth/" + code.toLowerCase().replace("error_", "").replace('_', '-'); + code = "auth/" + code + .toLowerCase() + .replace("error_", "") + .replace('_', '-'); error.putString("code", code); error.putString("message", message); error.putString("nativeErrorMessage", exception.getMessage()); @@ -1528,7 +1786,10 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule { * @param providerData List user.getProviderData() * @return WritableArray array */ - private WritableArray convertProviderData(List providerData, FirebaseUser user) { + private WritableArray convertProviderData( + List providerData, + FirebaseUser user + ) { WritableArray output = Arguments.createArray(); for (UserInfo userInfo : providerData) { // remove 'firebase' provider data - android fb sdk @@ -1666,7 +1927,12 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule { * @param type * @param state */ - private void sendPhoneStateEvent(String appName, String requestKey, String type, WritableMap state) { + private void sendPhoneStateEvent( + String appName, + String requestKey, + String type, + WritableMap state + ) { WritableMap eventMap = Arguments.createMap(); eventMap.putString("appName", appName); eventMap.putString("requestKey", requestKey); diff --git a/android/src/main/java/io/invertase/firebase/auth/RNFirebaseAuthPackage.java b/android/src/main/java/io/invertase/firebase/auth/RNFirebaseAuthPackage.java index 909b9312..1ed3c621 100644 --- a/android/src/main/java/io/invertase/firebase/auth/RNFirebaseAuthPackage.java +++ b/android/src/main/java/io/invertase/firebase/auth/RNFirebaseAuthPackage.java @@ -1,7 +1,6 @@ package io.invertase.firebase.auth; import com.facebook.react.ReactPackage; -import com.facebook.react.bridge.JavaScriptModule; import com.facebook.react.bridge.NativeModule; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.uimanager.UIManagerModule; diff --git a/android/src/main/java/io/invertase/firebase/config/RNFirebaseRemoteConfig.java b/android/src/main/java/io/invertase/firebase/config/RNFirebaseRemoteConfig.java index 4e1c5c09..054f9e0e 100644 --- a/android/src/main/java/io/invertase/firebase/config/RNFirebaseRemoteConfig.java +++ b/android/src/main/java/io/invertase/firebase/config/RNFirebaseRemoteConfig.java @@ -3,26 +3,25 @@ package io.invertase.firebase.config; import android.support.annotation.NonNull; import android.util.Log; -import com.google.android.gms.tasks.Task; -import com.facebook.react.bridge.Promise; import com.facebook.react.bridge.Arguments; -import com.facebook.react.bridge.ReactMethod; -import com.facebook.react.bridge.ReadableMap; -import com.facebook.react.bridge.WritableMap; -import com.facebook.react.bridge.ReadableArray; -import com.facebook.react.bridge.WritableArray; -import com.google.android.gms.tasks.OnCompleteListener; +import com.facebook.react.bridge.Promise; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; -import com.google.firebase.FirebaseApp; +import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.bridge.ReadableArray; +import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.bridge.WritableArray; +import com.facebook.react.bridge.WritableMap; +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.Task; import com.google.firebase.remoteconfig.FirebaseRemoteConfig; import com.google.firebase.remoteconfig.FirebaseRemoteConfigFetchThrottledException; -import com.google.firebase.remoteconfig.FirebaseRemoteConfigValue; import com.google.firebase.remoteconfig.FirebaseRemoteConfigSettings; +import com.google.firebase.remoteconfig.FirebaseRemoteConfigValue; +import java.util.List; import java.util.Map; import java.util.Set; -import java.util.List; import io.invertase.firebase.Utils; @@ -49,11 +48,14 @@ class RNFirebaseRemoteConfig extends ReactContextBaseJavaModule { return TAG; } - @ReactMethod public void enableDeveloperMode() { + @ReactMethod + public void enableDeveloperMode() { FirebaseRemoteConfigSettings.Builder settings = new FirebaseRemoteConfigSettings.Builder(); settings.setDeveloperModeEnabled(true); - FirebaseRemoteConfig.getInstance().setConfigSettings(settings.build()); + FirebaseRemoteConfig + .getInstance() + .setConfigSettings(settings.build()); } @ReactMethod @@ -68,13 +70,19 @@ class RNFirebaseRemoteConfig extends ReactContextBaseJavaModule { @ReactMethod public void activateFetched(final Promise promise) { - Boolean status = FirebaseRemoteConfig.getInstance().activateFetched(); + Boolean status = FirebaseRemoteConfig + .getInstance() + .activateFetched(); + promise.resolve(status); } @ReactMethod public void getValue(String key, final Promise promise) { - FirebaseRemoteConfigValue value = FirebaseRemoteConfig.getInstance().getValue(key); + FirebaseRemoteConfigValue value = FirebaseRemoteConfig + .getInstance() + .getValue(key); + promise.resolve(convertRemoteConfigValue(value)); } @@ -84,7 +92,10 @@ class RNFirebaseRemoteConfig extends ReactContextBaseJavaModule { List keysList = Utils.recursivelyDeconstructReadableArray(keys); for (Object key : keysList) { - FirebaseRemoteConfigValue value = FirebaseRemoteConfig.getInstance().getValue((String) key); + FirebaseRemoteConfigValue value = FirebaseRemoteConfig + .getInstance() + .getValue((String) key); + array.pushMap(convertRemoteConfigValue(value)); } @@ -93,7 +104,10 @@ class RNFirebaseRemoteConfig extends ReactContextBaseJavaModule { @ReactMethod public void getKeysByPrefix(String prefix, final Promise promise) { - Set keys = FirebaseRemoteConfig.getInstance().getKeysByPrefix(prefix); + Set keys = FirebaseRemoteConfig + .getInstance() + .getKeysByPrefix(prefix); + WritableArray array = Arguments.createArray(); for (String key : keys) { @@ -106,16 +120,26 @@ class RNFirebaseRemoteConfig extends ReactContextBaseJavaModule { @ReactMethod public void setDefaults(ReadableMap map) { Map convertedMap = Utils.recursivelyDeconstructReadableMap(map); - FirebaseRemoteConfig.getInstance().setDefaults(convertedMap); + FirebaseRemoteConfig + .getInstance() + .setDefaults(convertedMap); } @ReactMethod public void setDefaultsFromResource(int resourceId) { - FirebaseRemoteConfig.getInstance().setDefaults(resourceId); + FirebaseRemoteConfig + .getInstance() + .setDefaults(resourceId); } - private void fetchInternal(final Promise promise, Boolean withExpiration, long expirationDuration) { - FirebaseRemoteConfig.getInstance().fetch(withExpiration ? expirationDuration : 43200) // 12 hours default + private void fetchInternal( + final Promise promise, + Boolean withExpiration, + long expirationDuration + ) { + FirebaseRemoteConfig + .getInstance() + .fetch(withExpiration ? expirationDuration : 43200) // 12 hours default .addOnCompleteListener(new OnCompleteListener() { @Override public void onComplete(@NonNull Task task) { @@ -123,9 +147,17 @@ class RNFirebaseRemoteConfig extends ReactContextBaseJavaModule { promise.resolve(null); } else { if (task.getException() instanceof FirebaseRemoteConfigFetchThrottledException) { - promise.reject("config/throttled", "fetch() operation cannot be completed successfully, due to throttling.", task.getException()); + promise.reject( + "config/throttled", + "fetch() operation cannot be completed successfully, due to throttling.", + task.getException() + ); } else { - promise.reject("config/failure", "fetch() operation cannot be completed successfully.", task.getException()); + promise.reject( + "config/failure", + "fetch() operation cannot be completed successfully.", + task.getException() + ); } } } diff --git a/android/src/main/java/io/invertase/firebase/config/RNFirebaseRemoteConfigPackage.java b/android/src/main/java/io/invertase/firebase/config/RNFirebaseRemoteConfigPackage.java index dce06b80..22cb28fe 100644 --- a/android/src/main/java/io/invertase/firebase/config/RNFirebaseRemoteConfigPackage.java +++ b/android/src/main/java/io/invertase/firebase/config/RNFirebaseRemoteConfigPackage.java @@ -1,7 +1,6 @@ package io.invertase.firebase.config; import com.facebook.react.ReactPackage; -import com.facebook.react.bridge.JavaScriptModule; import com.facebook.react.bridge.NativeModule; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.uimanager.UIManagerModule; diff --git a/android/src/main/java/io/invertase/firebase/database/RNFirebaseDatabase.java b/android/src/main/java/io/invertase/firebase/database/RNFirebaseDatabase.java index cf51b626..d00756f3 100644 --- a/android/src/main/java/io/invertase/firebase/database/RNFirebaseDatabase.java +++ b/android/src/main/java/io/invertase/firebase/database/RNFirebaseDatabase.java @@ -4,26 +4,25 @@ import android.os.AsyncTask; import android.util.Log; import android.util.SparseArray; -import com.facebook.react.bridge.Promise; import com.facebook.react.bridge.Arguments; +import com.facebook.react.bridge.Promise; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactMethod; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.WritableMap; -import com.facebook.react.bridge.ReactApplicationContext; -import com.facebook.react.bridge.ReactContextBaseJavaModule; - import com.google.firebase.FirebaseApp; +import com.google.firebase.database.DataSnapshot; +import com.google.firebase.database.DatabaseError; import com.google.firebase.database.DatabaseException; +import com.google.firebase.database.DatabaseReference; +import com.google.firebase.database.FirebaseDatabase; import com.google.firebase.database.Logger; import com.google.firebase.database.MutableData; import com.google.firebase.database.OnDisconnect; import com.google.firebase.database.ServerValue; import com.google.firebase.database.Transaction; -import com.google.firebase.database.DataSnapshot; -import com.google.firebase.database.DatabaseError; -import com.google.firebase.database.FirebaseDatabase; -import com.google.firebase.database.DatabaseReference; import java.util.HashMap; import java.util.List; @@ -32,12 +31,11 @@ import java.util.Map; import io.invertase.firebase.ErrorUtils; import io.invertase.firebase.Utils; - public class RNFirebaseDatabase extends ReactContextBaseJavaModule { private static final String TAG = "RNFirebaseDatabase"; private static boolean enableLogging = false; - private HashMap references = new HashMap<>(); private static HashMap loggingLevelSet = new HashMap<>(); + private HashMap references = new HashMap<>(); private SparseArray transactionHandlers = new SparseArray<>(); RNFirebaseDatabase(ReactApplicationContext reactContext) { @@ -49,6 +47,210 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule { * REACT NATIVE METHODS */ + /** + * Resolve null or reject with a js like error if databaseError exists + * + * @param promise + * @param databaseError + */ + static void handlePromise(Promise promise, DatabaseError databaseError) { + if (databaseError != null) { + WritableMap jsError = getJSError(databaseError); + promise.reject( + jsError.getString("code"), + jsError.getString("message"), + databaseError.toException() + ); + } else { + promise.resolve(null); + } + } + + /** + * Get a database instance for a specific firebase app instance + * + * @param appName + * @param dbURL + * @return + */ + public static FirebaseDatabase getDatabaseForApp(String appName, String dbURL) { + FirebaseDatabase firebaseDatabase; + if (dbURL != null && dbURL.length() > 0) { + if (appName != null && appName.length() > 0) { + FirebaseApp firebaseApp = FirebaseApp.getInstance(appName); + firebaseDatabase = FirebaseDatabase.getInstance(firebaseApp, dbURL); + } else { + firebaseDatabase = FirebaseDatabase.getInstance(dbURL); + } + } else { + FirebaseApp firebaseApp = FirebaseApp.getInstance(appName); + firebaseDatabase = FirebaseDatabase.getInstance(firebaseApp); + } + + Boolean logLevel = loggingLevelSet.get(firebaseDatabase + .getApp() + .getName()); + + if (enableLogging && (logLevel == null || !logLevel)) { + try { + loggingLevelSet.put(firebaseDatabase + .getApp() + .getName(), enableLogging); + firebaseDatabase.setLogLevel(Logger.Level.DEBUG); + } catch (DatabaseException dex) { + // do nothing - to catch 'calls to setLogLevel must be made for use of database' errors + // only occurs in dev after reloading or if user has actually incorrectly called it. + Log.w( + TAG, + "WARNING: enableLogging(bool) must be called before any other use of database(). \n" + + "If you are sure you've done this then this message can be ignored during development as \n" + + "RN reloads can cause false positives. APP: " + firebaseDatabase + .getApp() + .getName() + ); + } + } else if (!enableLogging && (logLevel != null && logLevel)) { + try { + loggingLevelSet.put(firebaseDatabase + .getApp() + .getName(), enableLogging); + firebaseDatabase.setLogLevel(Logger.Level.WARN); + } catch (DatabaseException dex) { + // do nothing - to catch 'calls to setLogLevel must be made for use of database' errors + // only occurs in dev after reloading or if user has actually incorrectly called it. + Log.w( + TAG, + "WARNING: enableLogging(bool) must be called before any other use of database(). \n" + + "If you are sure you've done this then this message can be ignored during development as \n" + + "RN reloads can cause false positives. APP: " + firebaseDatabase + .getApp() + .getName() + ); + } + } + + return firebaseDatabase; + } + + /** + * Convert as firebase DatabaseError instance into a writable map + * with the correct web-like error codes. + * + * @param nativeError + * @return + */ + static WritableMap getJSError(DatabaseError nativeError) { + WritableMap errorMap = Arguments.createMap(); + errorMap.putInt("nativeErrorCode", nativeError.getCode()); + errorMap.putString("nativeErrorMessage", nativeError.getMessage()); + + String code; + String message; + String service = "Database"; + + switch (nativeError.getCode()) { + case DatabaseError.DATA_STALE: + code = ErrorUtils.getCodeWithService(service, "data-stale"); + message = ErrorUtils.getMessageWithService( + "The transaction needs to be run again with current data.", + service, + code + ); + break; + case DatabaseError.OPERATION_FAILED: + code = ErrorUtils.getCodeWithService(service, "failure"); + message = ErrorUtils.getMessageWithService( + "The server indicated that this operation failed.", + service, + code + ); + break; + case DatabaseError.PERMISSION_DENIED: + code = ErrorUtils.getCodeWithService(service, "permission-denied"); + message = ErrorUtils.getMessageWithService( + "Client doesn't have permission to access the desired data.", + service, + code + ); + break; + case DatabaseError.DISCONNECTED: + code = ErrorUtils.getCodeWithService(service, "disconnected"); + message = ErrorUtils.getMessageWithService( + "The operation had to be aborted due to a network disconnect.", + service, + code + ); + break; + case DatabaseError.EXPIRED_TOKEN: + code = ErrorUtils.getCodeWithService(service, "expired-token"); + message = ErrorUtils.getMessageWithService( + "The supplied auth token has expired.", + service, + code + ); + break; + case DatabaseError.INVALID_TOKEN: + code = ErrorUtils.getCodeWithService(service, "invalid-token"); + message = ErrorUtils.getMessageWithService( + "The supplied auth token was invalid.", + service, + code + ); + break; + case DatabaseError.MAX_RETRIES: + code = ErrorUtils.getCodeWithService(service, "max-retries"); + message = ErrorUtils.getMessageWithService( + "The transaction had too many retries.", + service, + code + ); + break; + case DatabaseError.OVERRIDDEN_BY_SET: + code = ErrorUtils.getCodeWithService(service, "overridden-by-set"); + message = ErrorUtils.getMessageWithService( + "The transaction was overridden by a subsequent set.", + service, + code + ); + break; + case DatabaseError.UNAVAILABLE: + code = ErrorUtils.getCodeWithService(service, "unavailable"); + message = ErrorUtils.getMessageWithService("The service is unavailable.", service, code); + break; + case DatabaseError.USER_CODE_EXCEPTION: + code = ErrorUtils.getCodeWithService(service, "user-code-exception"); + message = ErrorUtils.getMessageWithService( + "User code called from the Firebase Database runloop threw an exception.", + service, + code + ); + break; + case DatabaseError.NETWORK_ERROR: + code = ErrorUtils.getCodeWithService(service, "network-error"); + message = ErrorUtils.getMessageWithService( + "The operation could not be performed due to a network error.", + service, + code + ); + break; + case DatabaseError.WRITE_CANCELED: + code = ErrorUtils.getCodeWithService(service, "write-cancelled"); + message = ErrorUtils.getMessageWithService( + "The write was canceled by the user.", + service, + code + ); + break; + default: + code = ErrorUtils.getCodeWithService(service, "unknown"); + message = ErrorUtils.getMessageWithService("An unknown error occurred.", service, code); + } + + errorMap.putString("code", code); + errorMap.putString("message", message); + return errorMap; + } + /** * @param appName */ @@ -74,6 +276,11 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule { getDatabaseForApp(appName, dbURL).setPersistenceEnabled(state); } + + /* + * TRANSACTIONS + */ + /** * @param appName * @param size @@ -83,7 +290,6 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule { getDatabaseForApp(appName, dbURL).setPersistenceCacheSizeBytes((long) size); } - /** * @param enabled */ @@ -95,42 +301,62 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule { loggingLevelSet.put(app.getName(), enabled); try { if (enableLogging) { - FirebaseDatabase.getInstance(app).setLogLevel(Logger.Level.DEBUG); + FirebaseDatabase + .getInstance(app) + .setLogLevel(Logger.Level.DEBUG); } else { - FirebaseDatabase.getInstance(app).setLogLevel(Logger.Level.WARN); + FirebaseDatabase + .getInstance(app) + .setLogLevel(Logger.Level.WARN); } } catch (DatabaseException dex) { // do nothing - to catch 'calls to setLogLevel must be made for use of database' errors // only occurs in dev after reloading or if user has actually incorrectly called it. - Log.w(TAG, "WARNING: enableLogging(bool) must be called before any other use of database(). \n" + - "If you are sure you've done this then this message can be ignored during development as \n" + - "RN reloads can cause false positives. APP: " + app.getName()); + Log.w( + TAG, + "WARNING: enableLogging(bool) must be called before any other use of database(). \n" + + "If you are sure you've done this then this message can be ignored during development as \n" + + "RN reloads can cause false positives. APP: " + app.getName() + ); } } } + /* + * ON DISCONNECT + */ + /** * @param appName * @param path * @param state */ @ReactMethod - public void keepSynced(String appName, String dbURL, String key, String path, ReadableArray modifiers, Boolean state) { - getInternalReferenceForApp(appName, dbURL, key, path, modifiers).getQuery().keepSynced(state); + public void keepSynced( + String appName, + String dbURL, + String key, + String path, + ReadableArray modifiers, + Boolean state + ) { + getInternalReferenceForApp(appName, dbURL, key, path, modifiers) + .getQuery() + .keepSynced(state); } - - /* - * TRANSACTIONS - */ - /** * @param transactionId * @param updates */ @ReactMethod - public void transactionTryCommit(String appName, String dbURL, int transactionId, ReadableMap updates) { + public void transactionTryCommit( + String appName, + String dbURL, + int transactionId, + ReadableMap updates + ) { RNFirebaseTransactionHandler handler = transactionHandlers.get(transactionId); if (handler != null) { @@ -147,7 +373,13 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule { * @param applyLocally */ @ReactMethod - public void transactionStart(final String appName, final String dbURL, final String path, final int transactionId, final Boolean applyLocally) { + public void transactionStart( + final String appName, + final String dbURL, + final String path, + final int transactionId, + final Boolean applyLocally + ) { AsyncTask.execute(new Runnable() { @Override public void run() { @@ -156,7 +388,11 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule { reference.runTransaction(new Transaction.Handler() { @Override public Transaction.Result doTransaction(MutableData mutableData) { - final RNFirebaseTransactionHandler transactionHandler = new RNFirebaseTransactionHandler(transactionId, appName, dbURL); + final RNFirebaseTransactionHandler transactionHandler = new RNFirebaseTransactionHandler( + transactionId, + appName, + dbURL + ); transactionHandlers.put(transactionId, transactionHandler); final WritableMap updatesMap = transactionHandler.createUpdateMap(mutableData); @@ -165,7 +401,11 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule { AsyncTask.execute(new Runnable() { @Override public void run() { - Utils.sendEvent(getReactApplicationContext(), "database_transaction_event", updatesMap); + Utils.sendEvent( + getReactApplicationContext(), + "database_transaction_event", + updatesMap + ); } }); @@ -198,11 +438,6 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule { }); } - - /* - * ON DISCONNECT - */ - /** * Set a value on a ref when the client disconnects from the firebase server. * @@ -212,7 +447,13 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule { * @param promise */ @ReactMethod - public void onDisconnectSet(String appName, String dbURL, String path, ReadableMap props, final Promise promise) { + public void onDisconnectSet( + String appName, + String dbURL, + String path, + ReadableMap props, + final Promise promise + ) { String type = props.getString("type"); DatabaseReference ref = getReferenceForAppPath(appName, dbURL, path); @@ -257,7 +498,13 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule { * @param promise */ @ReactMethod - public void onDisconnectUpdate(String appName, String dbURL, String path, ReadableMap props, final Promise promise) { + public void onDisconnectUpdate( + String appName, + String dbURL, + String path, + ReadableMap props, + final Promise promise + ) { DatabaseReference ref = getReferenceForAppPath(appName, dbURL, path); OnDisconnect ondDisconnect = ref.onDisconnect(); @@ -318,9 +565,17 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule { * @param promise */ @ReactMethod - public void set(String appName, String dbURL, String path, ReadableMap props, final Promise promise) { + public void set( + String appName, + String dbURL, + String path, + ReadableMap props, + final Promise promise + ) { DatabaseReference ref = getReferenceForAppPath(appName, dbURL, path); - Object value = Utils.recursivelyDeconstructReadableMap(props).get("value"); + Object value = Utils + .recursivelyDeconstructReadableMap(props) + .get("value"); DatabaseReference.CompletionListener listener = new DatabaseReference.CompletionListener() { @Override @@ -339,9 +594,17 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule { * @param promise */ @ReactMethod - public void setPriority(String appName, String dbURL, String path, ReadableMap priority, final Promise promise) { + public void setPriority( + String appName, + String dbURL, + String path, + ReadableMap priority, + final Promise promise + ) { DatabaseReference ref = getReferenceForAppPath(appName, dbURL, path); - Object priorityValue = Utils.recursivelyDeconstructReadableMap(priority).get("value"); + Object priorityValue = Utils + .recursivelyDeconstructReadableMap(priority) + .get("value"); DatabaseReference.CompletionListener listener = new DatabaseReference.CompletionListener() { @Override @@ -361,10 +624,21 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule { * @param promise */ @ReactMethod - public void setWithPriority(String appName, String dbURL, String path, ReadableMap data, ReadableMap priority, final Promise promise) { + public void setWithPriority( + String appName, + String dbURL, + String path, + ReadableMap data, + ReadableMap priority, + final Promise promise + ) { DatabaseReference ref = getReferenceForAppPath(appName, dbURL, path); - Object dataValue = Utils.recursivelyDeconstructReadableMap(data).get("value"); - Object priorityValue = Utils.recursivelyDeconstructReadableMap(priority).get("value"); + Object dataValue = Utils + .recursivelyDeconstructReadableMap(data) + .get("value"); + Object priorityValue = Utils + .recursivelyDeconstructReadableMap(priority) + .get("value"); DatabaseReference.CompletionListener listener = new DatabaseReference.CompletionListener() { @Override @@ -383,7 +657,13 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule { * @param promise */ @ReactMethod - public void update(String appName, String dbURL, String path, ReadableMap props, final Promise promise) { + public void update( + String appName, + String dbURL, + String path, + ReadableMap props, + final Promise promise + ) { DatabaseReference ref = getReferenceForAppPath(appName, dbURL, path); Map updates = Utils.recursivelyDeconstructReadableMap(props); @@ -416,6 +696,9 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule { ref.removeValue(listener); } + /* + * INTERNALS/UTILS + */ /** * Subscribe once to a firebase reference. @@ -428,7 +711,15 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule { * @param promise */ @ReactMethod - public void once(String appName, String dbURL, String key, String path, ReadableArray modifiers, String eventType, Promise promise) { + public void once( + String appName, + String dbURL, + String key, + String path, + ReadableArray modifiers, + String eventType, + Promise promise + ) { getInternalReferenceForApp(appName, dbURL, key, path, modifiers).once(eventType, promise); } @@ -466,80 +757,6 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule { } } - /* - * INTERNALS/UTILS - */ - - /** - * Resolve null or reject with a js like error if databaseError exists - * - * @param promise - * @param databaseError - */ - static void handlePromise(Promise promise, DatabaseError databaseError) { - if (databaseError != null) { - WritableMap jsError = getJSError(databaseError); - promise.reject( - jsError.getString("code"), - jsError.getString("message"), - databaseError.toException() - ); - } else { - promise.resolve(null); - } - } - - - /** - * Get a database instance for a specific firebase app instance - * - * @param appName - * @param dbURL - * @return - */ - public static FirebaseDatabase getDatabaseForApp(String appName, String dbURL) { - FirebaseDatabase firebaseDatabase; - if(dbURL != null && dbURL.length() > 0) { - if (appName != null && appName.length() > 0) { - FirebaseApp firebaseApp = FirebaseApp.getInstance(appName); - firebaseDatabase = FirebaseDatabase.getInstance(firebaseApp, dbURL); - } else { - firebaseDatabase = FirebaseDatabase.getInstance(dbURL); - } - } else { - FirebaseApp firebaseApp = FirebaseApp.getInstance(appName); - firebaseDatabase = FirebaseDatabase.getInstance(firebaseApp); - } - - Boolean logLevel = loggingLevelSet.get(firebaseDatabase.getApp().getName()); - - if (enableLogging && (logLevel == null || !logLevel)) { - try { - loggingLevelSet.put(firebaseDatabase.getApp().getName(), enableLogging); - firebaseDatabase.setLogLevel(Logger.Level.DEBUG); - } catch (DatabaseException dex) { - // do nothing - to catch 'calls to setLogLevel must be made for use of database' errors - // only occurs in dev after reloading or if user has actually incorrectly called it. - Log.w(TAG, "WARNING: enableLogging(bool) must be called before any other use of database(). \n" + - "If you are sure you've done this then this message can be ignored during development as \n" + - "RN reloads can cause false positives. APP: " + firebaseDatabase.getApp().getName()); - } - } else if (!enableLogging && (logLevel != null && logLevel)) { - try { - loggingLevelSet.put(firebaseDatabase.getApp().getName(), enableLogging); - firebaseDatabase.setLogLevel(Logger.Level.WARN); - } catch (DatabaseException dex) { - // do nothing - to catch 'calls to setLogLevel must be made for use of database' errors - // only occurs in dev after reloading or if user has actually incorrectly called it. - Log.w(TAG, "WARNING: enableLogging(bool) must be called before any other use of database(). \n" + - "If you are sure you've done this then this message can be ignored during development as \n" + - "RN reloads can cause false positives. APP: " + firebaseDatabase.getApp().getName()); - } - } - - return firebaseDatabase; - } - /** * Get a database reference for a specific app and path * @@ -560,7 +777,13 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule { * @param modifiers * @return */ - private RNFirebaseDatabaseReference getInternalReferenceForApp(String appName, String dbURL, String key, String path, ReadableArray modifiers) { + private RNFirebaseDatabaseReference getInternalReferenceForApp( + String appName, + String dbURL, + String key, + String path, + ReadableArray modifiers + ) { return new RNFirebaseDatabaseReference( getReactApplicationContext(), appName, @@ -578,7 +801,11 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule { * @param props * @return */ - private RNFirebaseDatabaseReference getCachedInternalReferenceForApp(String appName, String dbURL, ReadableMap props) { + private RNFirebaseDatabaseReference getCachedInternalReferenceForApp( + String appName, + String dbURL, + ReadableMap props + ) { String key = props.getString("key"); String path = props.getString("path"); ReadableArray modifiers = props.getArray("modifiers"); @@ -593,81 +820,6 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule { return existingRef; } - /** - * Convert as firebase DatabaseError instance into a writable map - * with the correct web-like error codes. - * - * @param nativeError - * @return - */ - static WritableMap getJSError(DatabaseError nativeError) { - WritableMap errorMap = Arguments.createMap(); - errorMap.putInt("nativeErrorCode", nativeError.getCode()); - errorMap.putString("nativeErrorMessage", nativeError.getMessage()); - - String code; - String message; - String service = "Database"; - - switch (nativeError.getCode()) { - case DatabaseError.DATA_STALE: - code = ErrorUtils.getCodeWithService(service, "data-stale"); - message = ErrorUtils.getMessageWithService("The transaction needs to be run again with current data.", service, code); - break; - case DatabaseError.OPERATION_FAILED: - code = ErrorUtils.getCodeWithService(service, "failure"); - message = ErrorUtils.getMessageWithService("The server indicated that this operation failed.", service, code); - break; - case DatabaseError.PERMISSION_DENIED: - code = ErrorUtils.getCodeWithService(service, "permission-denied"); - message = ErrorUtils.getMessageWithService("Client doesn't have permission to access the desired data.", service, code); - break; - case DatabaseError.DISCONNECTED: - code = ErrorUtils.getCodeWithService(service, "disconnected"); - message = ErrorUtils.getMessageWithService("The operation had to be aborted due to a network disconnect.", service, code); - break; - case DatabaseError.EXPIRED_TOKEN: - code = ErrorUtils.getCodeWithService(service, "expired-token"); - message = ErrorUtils.getMessageWithService("The supplied auth token has expired.", service, code); - break; - case DatabaseError.INVALID_TOKEN: - code = ErrorUtils.getCodeWithService(service, "invalid-token"); - message = ErrorUtils.getMessageWithService("The supplied auth token was invalid.", service, code); - break; - case DatabaseError.MAX_RETRIES: - code = ErrorUtils.getCodeWithService(service, "max-retries"); - message = ErrorUtils.getMessageWithService("The transaction had too many retries.", service, code); - break; - case DatabaseError.OVERRIDDEN_BY_SET: - code = ErrorUtils.getCodeWithService(service, "overridden-by-set"); - message = ErrorUtils.getMessageWithService("The transaction was overridden by a subsequent set.", service, code); - break; - case DatabaseError.UNAVAILABLE: - code = ErrorUtils.getCodeWithService(service, "unavailable"); - message = ErrorUtils.getMessageWithService("The service is unavailable.", service, code); - break; - case DatabaseError.USER_CODE_EXCEPTION: - code = ErrorUtils.getCodeWithService(service, "user-code-exception"); - message = ErrorUtils.getMessageWithService("User code called from the Firebase Database runloop threw an exception.", service, code); - break; - case DatabaseError.NETWORK_ERROR: - code = ErrorUtils.getCodeWithService(service, "network-error"); - message = ErrorUtils.getMessageWithService("The operation could not be performed due to a network error.", service, code); - break; - case DatabaseError.WRITE_CANCELED: - code = ErrorUtils.getCodeWithService(service, "write-cancelled"); - message = ErrorUtils.getMessageWithService("The write was canceled by the user.", service, code); - break; - default: - code = ErrorUtils.getCodeWithService(service, "unknown"); - message = ErrorUtils.getMessageWithService("An unknown error occurred.", service, code); - } - - errorMap.putString("code", code); - errorMap.putString("message", message); - return errorMap; - } - /** * React Method - returns this module name * diff --git a/android/src/main/java/io/invertase/firebase/database/RNFirebaseDatabasePackage.java b/android/src/main/java/io/invertase/firebase/database/RNFirebaseDatabasePackage.java index c4e9808d..1711e0da 100644 --- a/android/src/main/java/io/invertase/firebase/database/RNFirebaseDatabasePackage.java +++ b/android/src/main/java/io/invertase/firebase/database/RNFirebaseDatabasePackage.java @@ -1,7 +1,6 @@ package io.invertase.firebase.database; import com.facebook.react.ReactPackage; -import com.facebook.react.bridge.JavaScriptModule; import com.facebook.react.bridge.NativeModule; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.uimanager.UIManagerModule; diff --git a/android/src/main/java/io/invertase/firebase/database/RNFirebaseDatabaseReference.java b/android/src/main/java/io/invertase/firebase/database/RNFirebaseDatabaseReference.java index 947992c8..5ccb7b88 100644 --- a/android/src/main/java/io/invertase/firebase/database/RNFirebaseDatabaseReference.java +++ b/android/src/main/java/io/invertase/firebase/database/RNFirebaseDatabaseReference.java @@ -1,82 +1,41 @@ package io.invertase.firebase.database; -import java.util.Map; -import java.util.List; -import java.util.HashMap; -import java.lang.ref.WeakReference; - -import android.util.Log; -import android.os.AsyncTask; import android.annotation.SuppressLint; +import android.os.AsyncTask; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.util.Log; -import com.facebook.react.bridge.Promise; import com.facebook.react.bridge.Arguments; -import com.facebook.react.bridge.ReadableMap; -import com.facebook.react.bridge.WritableMap; +import com.facebook.react.bridge.Promise; import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.ReadableArray; - -import com.google.firebase.database.Query; +import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.bridge.WritableMap; +import com.google.firebase.database.ChildEventListener; import com.google.firebase.database.DataSnapshot; import com.google.firebase.database.DatabaseError; import com.google.firebase.database.FirebaseDatabase; -import com.google.firebase.database.ChildEventListener; +import com.google.firebase.database.Query; import com.google.firebase.database.ValueEventListener; +import java.lang.ref.WeakReference; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + import io.invertase.firebase.Utils; class RNFirebaseDatabaseReference { + private static final String TAG = "RNFirebaseDBReference"; private String key; private Query query; private String appName; private String dbURL; private ReactContext reactContext; - private static final String TAG = "RNFirebaseDBReference"; private HashMap childEventListeners = new HashMap<>(); private HashMap valueEventListeners = new HashMap<>(); - /** - * AsyncTask to convert DataSnapshot instances to WritableMap instances. - * - * Introduced due to https://github.com/invertase/react-native-firebase/issues/1284 - */ - private static class DataSnapshotToMapAsyncTask extends AsyncTask { - - private WeakReference reactContextWeakReference; - private WeakReference referenceWeakReference; - - DataSnapshotToMapAsyncTask(ReactContext context, RNFirebaseDatabaseReference reference) { - referenceWeakReference = new WeakReference<>(reference); - reactContextWeakReference = new WeakReference<>(context); - } - - @Override - protected final WritableMap doInBackground(Object... params) { - DataSnapshot dataSnapshot = (DataSnapshot) params[0]; - @Nullable String previousChildName = (String) params[1]; - - try { - return RNFirebaseDatabaseUtils.snapshotToMap(dataSnapshot, previousChildName); - } catch (RuntimeException e) { - if (isAvailable()) { - reactContextWeakReference.get().handleException(e); - } - throw e; - } - } - - @Override - protected void onPostExecute(WritableMap writableMap) { - // do nothing as overridden on usage - } - - Boolean isAvailable() { - return reactContextWeakReference.get() != null && referenceWeakReference.get() != null; - } - } - /** * RNFirebase wrapper around FirebaseDatabaseReference, * handles Query generation and event listeners. @@ -87,7 +46,14 @@ class RNFirebaseDatabaseReference { * @param refPath * @param modifiersArray */ - RNFirebaseDatabaseReference(ReactContext context, String app, String url, String refKey, String refPath, ReadableArray modifiersArray) { + RNFirebaseDatabaseReference( + ReactContext context, + String app, + String url, + String refKey, + String refPath, + ReadableArray modifiersArray + ) { key = refKey; query = null; appName = app; @@ -96,7 +62,6 @@ class RNFirebaseDatabaseReference { buildDatabaseQueryAtPathAndModifiers(refPath, modifiersArray); } - /** * Used outside of class for keepSynced etc. * @@ -113,7 +78,8 @@ class RNFirebaseDatabaseReference { * @return */ private Boolean hasEventListener(String eventRegistrationKey) { - return valueEventListeners.containsKey(eventRegistrationKey) || childEventListeners.containsKey(eventRegistrationKey); + return valueEventListeners.containsKey(eventRegistrationKey) || childEventListeners.containsKey( + eventRegistrationKey); } /** @@ -155,7 +121,6 @@ class RNFirebaseDatabaseReference { } - /** * Add a ChildEventListener to the query and internally keep a reference to it. * @@ -174,8 +139,10 @@ class RNFirebaseDatabaseReference { * @param promise */ private void addOnceValueEventListener(final Promise promise) { - @SuppressLint("StaticFieldLeak") - final DataSnapshotToMapAsyncTask asyncTask = new DataSnapshotToMapAsyncTask(reactContext, this) { + @SuppressLint("StaticFieldLeak") final DataSnapshotToMapAsyncTask asyncTask = new DataSnapshotToMapAsyncTask( + reactContext, + this + ) { @Override protected void onPostExecute(WritableMap writableMap) { if (this.isAvailable()) promise.resolve(writableMap); @@ -252,7 +219,6 @@ class RNFirebaseDatabaseReference { query.addChildEventListener(childEventListener); } - /** * Handles a React Native JS '.on(..)' request and initializes listeners. * @@ -280,7 +246,6 @@ class RNFirebaseDatabaseReference { } } - /** * Add a native .on('child_X',.. ) event listener. * @@ -365,7 +330,12 @@ class RNFirebaseDatabaseReference { * @param dataSnapshot * @param previousChildName */ - private void handleDatabaseEvent(final String eventType, final ReadableMap registration, DataSnapshot dataSnapshot, @Nullable String previousChildName) { + private void handleDatabaseEvent( + final String eventType, + final ReadableMap registration, + DataSnapshot dataSnapshot, + @Nullable String previousChildName + ) { @SuppressLint("StaticFieldLeak") DataSnapshotToMapAsyncTask asyncTask = new DataSnapshotToMapAsyncTask(reactContext, this) { @Override @@ -424,11 +394,6 @@ class RNFirebaseDatabaseReference { } } - /* ================= - * QUERY MODIFIERS - * ================= - */ - /** * @param name * @param type @@ -451,6 +416,11 @@ class RNFirebaseDatabaseReference { } } + /* ================= + * QUERY MODIFIERS + * ================= + */ + /** * @param name * @param type @@ -481,12 +451,6 @@ class RNFirebaseDatabaseReference { } } - - /* =============== - * QUERY FILTERS - * =============== - */ - /** * @param key * @param valueType @@ -517,6 +481,12 @@ class RNFirebaseDatabaseReference { } } + + /* =============== + * QUERY FILTERS + * =============== + */ + /** * @param key * @param valueType @@ -576,4 +546,46 @@ class RNFirebaseDatabaseReference { } } } + + /** + * AsyncTask to convert DataSnapshot instances to WritableMap instances. + *

+ * Introduced due to https://github.com/invertase/react-native-firebase/issues/1284 + */ + private static class DataSnapshotToMapAsyncTask extends AsyncTask { + + private WeakReference reactContextWeakReference; + private WeakReference referenceWeakReference; + + DataSnapshotToMapAsyncTask(ReactContext context, RNFirebaseDatabaseReference reference) { + referenceWeakReference = new WeakReference<>(reference); + reactContextWeakReference = new WeakReference<>(context); + } + + @Override + protected final WritableMap doInBackground(Object... params) { + DataSnapshot dataSnapshot = (DataSnapshot) params[0]; + @Nullable String previousChildName = (String) params[1]; + + try { + return RNFirebaseDatabaseUtils.snapshotToMap(dataSnapshot, previousChildName); + } catch (RuntimeException e) { + if (isAvailable()) { + reactContextWeakReference + .get() + .handleException(e); + } + throw e; + } + } + + @Override + protected void onPostExecute(WritableMap writableMap) { + // do nothing as overridden on usage + } + + Boolean isAvailable() { + return reactContextWeakReference.get() != null && referenceWeakReference.get() != null; + } + } } diff --git a/android/src/main/java/io/invertase/firebase/database/RNFirebaseDatabaseUtils.java b/android/src/main/java/io/invertase/firebase/database/RNFirebaseDatabaseUtils.java index 71d64573..dbfa4bda 100644 --- a/android/src/main/java/io/invertase/firebase/database/RNFirebaseDatabaseUtils.java +++ b/android/src/main/java/io/invertase/firebase/database/RNFirebaseDatabaseUtils.java @@ -20,7 +20,10 @@ public class RNFirebaseDatabaseUtils { * @param previousChildName * @return */ - public static WritableMap snapshotToMap(DataSnapshot dataSnapshot, @Nullable String previousChildName) { + public static WritableMap snapshotToMap( + DataSnapshot dataSnapshot, + @Nullable String previousChildName + ) { WritableMap result = Arguments.createMap(); WritableMap snapshot = snapshotToMap(dataSnapshot); @@ -71,7 +74,10 @@ public class RNFirebaseDatabaseUtils { } } else { if (snapshot.getValue() != null) { - String type = snapshot.getValue().getClass().getName(); + String type = snapshot + .getValue() + .getClass() + .getName(); switch (type) { case "java.lang.Boolean": case "java.lang.Long": @@ -101,7 +107,10 @@ public class RNFirebaseDatabaseUtils { } } else { if (mutableData.getValue() != null) { - String type = mutableData.getValue().getClass().getName(); + String type = mutableData + .getValue() + .getClass() + .getName(); switch (type) { case "java.lang.Boolean": case "java.lang.Long": @@ -190,7 +199,9 @@ public class RNFirebaseDatabaseUtils { expectedKey = key; } Any castedChild = castValue(child); - switch (castedChild.getClass().getName()) { + switch (castedChild + .getClass() + .getName()) { case "java.lang.Boolean": array.pushBoolean((Boolean) castedChild); break; @@ -211,7 +222,12 @@ public class RNFirebaseDatabaseUtils { array.pushArray((WritableArray) castedChild); break; default: - Log.w(TAG, "Invalid type: " + castedChild.getClass().getName()); + Log.w( + TAG, + "Invalid type: " + castedChild + .getClass() + .getName() + ); break; } expectedKey++; @@ -236,7 +252,9 @@ public class RNFirebaseDatabaseUtils { expectedKey = key; } Any castedChild = castValue(child); - switch (castedChild.getClass().getName()) { + switch (castedChild + .getClass() + .getName()) { case "java.lang.Boolean": array.pushBoolean((Boolean) castedChild); break; @@ -257,7 +275,12 @@ public class RNFirebaseDatabaseUtils { array.pushArray((WritableArray) castedChild); break; default: - Log.w(TAG, "Invalid type: " + castedChild.getClass().getName()); + Log.w( + TAG, + "Invalid type: " + castedChild + .getClass() + .getName() + ); break; } expectedKey++; @@ -275,7 +298,9 @@ public class RNFirebaseDatabaseUtils { for (DataSnapshot child : snapshot.getChildren()) { Any castedChild = castValue(child); - switch (castedChild.getClass().getName()) { + switch (castedChild + .getClass() + .getName()) { case "java.lang.Boolean": map.putBoolean(child.getKey(), (Boolean) castedChild); break; @@ -295,7 +320,12 @@ public class RNFirebaseDatabaseUtils { map.putArray(child.getKey(), (WritableArray) castedChild); break; default: - Log.w(TAG, "Invalid type: " + castedChild.getClass().getName()); + Log.w( + TAG, + "Invalid type: " + castedChild + .getClass() + .getName() + ); break; } } @@ -312,7 +342,9 @@ public class RNFirebaseDatabaseUtils { for (MutableData child : mutableData.getChildren()) { Any castedChild = castValue(child); - switch (castedChild.getClass().getName()) { + switch (castedChild + .getClass() + .getName()) { case "java.lang.Boolean": map.putBoolean(child.getKey(), (Boolean) castedChild); break; @@ -332,7 +364,12 @@ public class RNFirebaseDatabaseUtils { map.putArray(child.getKey(), (WritableArray) castedChild); break; default: - Log.w(TAG, "Invalid type: " + castedChild.getClass().getName()); + Log.w( + TAG, + "Invalid type: " + castedChild + .getClass() + .getName() + ); break; } } diff --git a/android/src/main/java/io/invertase/firebase/database/RNFirebaseTransactionHandler.java b/android/src/main/java/io/invertase/firebase/database/RNFirebaseTransactionHandler.java index 1f5dd6ed..33babdb6 100644 --- a/android/src/main/java/io/invertase/firebase/database/RNFirebaseTransactionHandler.java +++ b/android/src/main/java/io/invertase/firebase/database/RNFirebaseTransactionHandler.java @@ -19,18 +19,17 @@ import javax.annotation.Nullable; import io.invertase.firebase.Utils; public class RNFirebaseTransactionHandler { - private int transactionId; - private String appName; - private String dbURL; private final ReentrantLock lock; private final Condition condition; - private Map data; - private boolean signalled; - public Object value; boolean interrupted; boolean abort = false; boolean timeout = false; + private int transactionId; + private String appName; + private String dbURL; + private Map data; + private boolean signalled; RNFirebaseTransactionHandler(int id, String app, String url) { appName = app; @@ -127,7 +126,11 @@ public class RNFirebaseTransactionHandler { } - WritableMap createResultMap(@Nullable DatabaseError error, boolean committed, DataSnapshot snapshot) { + WritableMap createResultMap( + @Nullable DatabaseError error, + boolean committed, + DataSnapshot snapshot + ) { WritableMap resultMap = Arguments.createMap(); resultMap.putInt("id", transactionId); @@ -144,7 +147,10 @@ public class RNFirebaseTransactionHandler { if (error == null && timeout) { WritableMap timeoutError = Arguments.createMap(); timeoutError.putString("code", "DATABASE/INTERNAL-TIMEOUT"); - timeoutError.putString("message", "A timeout occurred whilst waiting for RN JS thread to send transaction updates."); + timeoutError.putString( + "message", + "A timeout occurred whilst waiting for RN JS thread to send transaction updates." + ); resultMap.putMap("error", timeoutError); } } else { diff --git a/android/src/main/java/io/invertase/firebase/fabric/crashlytics/RNFirebaseCrashlytics.java b/android/src/main/java/io/invertase/firebase/fabric/crashlytics/RNFirebaseCrashlytics.java index f70a4732..a0d101ec 100644 --- a/android/src/main/java/io/invertase/firebase/fabric/crashlytics/RNFirebaseCrashlytics.java +++ b/android/src/main/java/io/invertase/firebase/fabric/crashlytics/RNFirebaseCrashlytics.java @@ -2,11 +2,10 @@ package io.invertase.firebase.fabric.crashlytics; import android.util.Log; -import com.facebook.react.bridge.ReactMethod; +import com.crashlytics.android.Crashlytics; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; - -import com.crashlytics.android.Crashlytics; +import com.facebook.react.bridge.ReactMethod; public class RNFirebaseCrashlytics extends ReactContextBaseJavaModule { @@ -25,7 +24,9 @@ public class RNFirebaseCrashlytics extends ReactContextBaseJavaModule { @ReactMethod public void crash() { - Crashlytics.getInstance().crash(); + Crashlytics + .getInstance() + .crash(); } @ReactMethod diff --git a/android/src/main/java/io/invertase/firebase/fabric/crashlytics/RNFirebaseCrashlyticsPackage.java b/android/src/main/java/io/invertase/firebase/fabric/crashlytics/RNFirebaseCrashlyticsPackage.java index 404f722a..44f31e37 100644 --- a/android/src/main/java/io/invertase/firebase/fabric/crashlytics/RNFirebaseCrashlyticsPackage.java +++ b/android/src/main/java/io/invertase/firebase/fabric/crashlytics/RNFirebaseCrashlyticsPackage.java @@ -1,7 +1,6 @@ package io.invertase.firebase.fabric.crashlytics; import com.facebook.react.ReactPackage; -import com.facebook.react.bridge.JavaScriptModule; import com.facebook.react.bridge.NativeModule; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.uimanager.UIManagerModule; diff --git a/android/src/main/java/io/invertase/firebase/firestore/DocumentSnapshotSerializeAsyncTask.java b/android/src/main/java/io/invertase/firebase/firestore/DocumentSnapshotSerializeAsyncTask.java index ebf77162..520ed6b4 100644 --- a/android/src/main/java/io/invertase/firebase/firestore/DocumentSnapshotSerializeAsyncTask.java +++ b/android/src/main/java/io/invertase/firebase/firestore/DocumentSnapshotSerializeAsyncTask.java @@ -28,7 +28,9 @@ class DocumentSnapshotSerializeAsyncTask extends AsyncTask transactionHandlers = new SparseArray<>(); @@ -83,7 +82,12 @@ public class RNFirebaseFirestore extends ReactContextBaseJavaModule { */ static WritableMap getJSError(FirebaseFirestoreException nativeException) { WritableMap errorMap = Arguments.createMap(); - errorMap.putInt("nativeErrorCode", nativeException.getCode().value()); + errorMap.putInt( + "nativeErrorCode", + nativeException + .getCode() + .value() + ); errorMap.putString("nativeErrorMessage", nativeException.getMessage()); String code; @@ -228,21 +232,23 @@ public class RNFirebaseFirestore extends ReactContextBaseJavaModule { @ReactMethod public void disableNetwork(String appName, final Promise promise) { - getFirestoreForApp(appName).disableNetwork().addOnCompleteListener(new OnCompleteListener() { - @Override - public void onComplete(@NonNull Task task) { - if (task.isSuccessful()) { - Log.d(TAG, "disableNetwork:onComplete:success"); - promise.resolve(null); - } else { - Log.e(TAG, "disableNetwork:onComplete:failure", task.getException()); - RNFirebaseFirestore.promiseRejectException( - promise, - (FirebaseFirestoreException) task.getException() - ); + getFirestoreForApp(appName) + .disableNetwork() + .addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + Log.d(TAG, "disableNetwork:onComplete:success"); + promise.resolve(null); + } else { + Log.e(TAG, "disableNetwork:onComplete:failure", task.getException()); + RNFirebaseFirestore.promiseRejectException( + promise, + (FirebaseFirestoreException) task.getException() + ); + } } - } - }); + }); } @ReactMethod @@ -256,21 +262,23 @@ public class RNFirebaseFirestore extends ReactContextBaseJavaModule { @ReactMethod public void enableNetwork(String appName, final Promise promise) { - getFirestoreForApp(appName).enableNetwork().addOnCompleteListener(new OnCompleteListener() { - @Override - public void onComplete(@NonNull Task task) { - if (task.isSuccessful()) { - Log.d(TAG, "enableNetwork:onComplete:success"); - promise.resolve(null); - } else { - Log.e(TAG, "enableNetwork:onComplete:failure", task.getException()); - RNFirebaseFirestore.promiseRejectException( - promise, - (FirebaseFirestoreException) task.getException() - ); + getFirestoreForApp(appName) + .enableNetwork() + .addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + Log.d(TAG, "enableNetwork:onComplete:success"); + promise.resolve(null); + } else { + Log.e(TAG, "enableNetwork:onComplete:failure", task.getException()); + RNFirebaseFirestore.promiseRejectException( + promise, + (FirebaseFirestoreException) task.getException() + ); + } } - } - }); + }); } @ReactMethod @@ -314,8 +322,10 @@ public class RNFirebaseFirestore extends ReactContextBaseJavaModule { } @ReactMethod - public void documentBatch(final String appName, final ReadableArray writes, - final Promise promise) { + public void documentBatch( + final String appName, final ReadableArray writes, + final Promise promise + ) { FirebaseFirestore firestore = getFirestoreForApp(appName); WriteBatch batch = firestore.batch(); final List writesArray = FirestoreSerialize.parseDocumentBatches(firestore, writes); @@ -346,18 +356,23 @@ public class RNFirebaseFirestore extends ReactContextBaseJavaModule { } } - batch.commit().addOnCompleteListener(new OnCompleteListener() { - @Override - public void onComplete(@NonNull Task task) { - if (task.isSuccessful()) { - Log.d(TAG, "documentBatch:onComplete:success"); - promise.resolve(null); - } else { - Log.e(TAG, "documentBatch:onComplete:failure", task.getException()); - RNFirebaseFirestore.promiseRejectException(promise, (FirebaseFirestoreException) task.getException()); + batch + .commit() + .addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + Log.d(TAG, "documentBatch:onComplete:success"); + promise.resolve(null); + } else { + Log.e(TAG, "documentBatch:onComplete:failure", task.getException()); + RNFirebaseFirestore.promiseRejectException( + promise, + (FirebaseFirestoreException) task.getException() + ); + } } - } - }); + }); } @ReactMethod @@ -421,17 +436,23 @@ public class RNFirebaseFirestore extends ReactContextBaseJavaModule { if (settings.hasKey("host")) { firestoreSettings.setHost(settings.getString("host")); } else { - firestoreSettings.setHost(firestore.getFirestoreSettings().getHost()); + firestoreSettings.setHost(firestore + .getFirestoreSettings() + .getHost()); } if (settings.hasKey("persistence")) { firestoreSettings.setPersistenceEnabled(settings.getBoolean("persistence")); } else { - firestoreSettings.setPersistenceEnabled(firestore.getFirestoreSettings().isPersistenceEnabled()); + firestoreSettings.setPersistenceEnabled(firestore + .getFirestoreSettings() + .isPersistenceEnabled()); } if (settings.hasKey("ssl")) { firestoreSettings.setSslEnabled(settings.getBoolean("ssl")); } else { - firestoreSettings.setSslEnabled(firestore.getFirestoreSettings().isSslEnabled()); + firestoreSettings.setSslEnabled(firestore + .getFirestoreSettings() + .isSslEnabled()); } // if (settings.hasKey("timestampsInSnapshots")) { @@ -731,8 +752,18 @@ public class RNFirebaseFirestore extends ReactContextBaseJavaModule { @Override public Map getConstants() { final Map constants = new HashMap<>(); - constants.put("deleteFieldValue", FieldValue.delete().toString()); - constants.put("serverTimestampFieldValue", FieldValue.serverTimestamp().toString()); + constants.put( + "deleteFieldValue", + FieldValue + .delete() + .toString() + ); + constants.put( + "serverTimestampFieldValue", + FieldValue + .serverTimestamp() + .toString() + ); return constants; } } diff --git a/android/src/main/java/io/invertase/firebase/firestore/RNFirebaseFirestoreCollectionReference.java b/android/src/main/java/io/invertase/firebase/firestore/RNFirebaseFirestoreCollectionReference.java index b251ec5f..eddb36cc 100644 --- a/android/src/main/java/io/invertase/firebase/firestore/RNFirebaseFirestoreCollectionReference.java +++ b/android/src/main/java/io/invertase/firebase/firestore/RNFirebaseFirestoreCollectionReference.java @@ -89,21 +89,23 @@ class RNFirebaseFirestoreCollectionReference { } }; - query.get(source).addOnCompleteListener(new OnCompleteListener() { - @Override - public void onComplete(@NonNull Task task) { - if (task.isSuccessful()) { - Log.d(TAG, "get:onComplete:success"); - serializeAsyncTask.execute(task.getResult()); - } else { - Log.e(TAG, "get:onComplete:failure", task.getException()); - RNFirebaseFirestore.promiseRejectException( - promise, - (FirebaseFirestoreException) task.getException() - ); + query + .get(source) + .addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + Log.d(TAG, "get:onComplete:success"); + serializeAsyncTask.execute(task.getResult()); + } else { + Log.e(TAG, "get:onComplete:failure", task.getException()); + RNFirebaseFirestore.promiseRejectException( + promise, + (FirebaseFirestoreException) task.getException() + ); + } } - } - }); + }); } void onSnapshot(final String listenerId, final ReadableMap queryListenOptions) { diff --git a/android/src/main/java/io/invertase/firebase/firestore/RNFirebaseFirestoreDocumentReference.java b/android/src/main/java/io/invertase/firebase/firestore/RNFirebaseFirestoreDocumentReference.java index 2690afa1..33500b34 100644 --- a/android/src/main/java/io/invertase/firebase/firestore/RNFirebaseFirestoreDocumentReference.java +++ b/android/src/main/java/io/invertase/firebase/firestore/RNFirebaseFirestoreDocumentReference.java @@ -39,7 +39,9 @@ public class RNFirebaseFirestoreDocumentReference { this.path = path; this.appName = appName; this.reactContext = reactContext; - this.ref = RNFirebaseFirestore.getFirestoreForApp(appName).document(path); + this.ref = RNFirebaseFirestore + .getFirestoreForApp(appName) + .document(path); } static void offSnapshot(final String listenerId) { @@ -50,21 +52,23 @@ public class RNFirebaseFirestoreDocumentReference { } void delete(final Promise promise) { - this.ref.delete().addOnCompleteListener(new OnCompleteListener() { - @Override - public void onComplete(@NonNull Task task) { - if (task.isSuccessful()) { - Log.d(TAG, "delete:onComplete:success"); - promise.resolve(null); - } else { - Log.e(TAG, "delete:onComplete:failure", task.getException()); - RNFirebaseFirestore.promiseRejectException( - promise, - (FirebaseFirestoreException) task.getException() - ); + this.ref + .delete() + .addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + Log.d(TAG, "delete:onComplete:success"); + promise.resolve(null); + } else { + Log.e(TAG, "delete:onComplete:failure", task.getException()); + RNFirebaseFirestore.promiseRejectException( + promise, + (FirebaseFirestoreException) task.getException() + ); + } } - } - }); + }); } void get(final ReadableMap getOptions, final Promise promise) { @@ -92,21 +96,23 @@ public class RNFirebaseFirestoreDocumentReference { } }; - this.ref.get(source).addOnCompleteListener(new OnCompleteListener() { - @Override - public void onComplete(@NonNull Task task) { - if (task.isSuccessful()) { - Log.d(TAG, "get:onComplete:success"); - serializeAsyncTask.execute(task.getResult()); - } else { - Log.e(TAG, "get:onComplete:failure", task.getException()); - RNFirebaseFirestore.promiseRejectException( - promise, - (FirebaseFirestoreException) task.getException() - ); + this.ref + .get(source) + .addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + Log.d(TAG, "get:onComplete:success"); + serializeAsyncTask.execute(task.getResult()); + } else { + Log.e(TAG, "get:onComplete:failure", task.getException()); + RNFirebaseFirestore.promiseRejectException( + promise, + (FirebaseFirestoreException) task.getException() + ); + } } - } - }); + }); } void onSnapshot(final String listenerId, final ReadableMap docListenOptions) { @@ -187,21 +193,23 @@ public class RNFirebaseFirestoreDocumentReference { data ); - this.ref.update(map).addOnCompleteListener(new OnCompleteListener() { - @Override - public void onComplete(@NonNull Task task) { - if (task.isSuccessful()) { - Log.d(TAG, "update:onComplete:success"); - promise.resolve(null); - } else { - Log.e(TAG, "update:onComplete:failure", task.getException()); - RNFirebaseFirestore.promiseRejectException( - promise, - (FirebaseFirestoreException) task.getException() - ); + this.ref + .update(map) + .addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + Log.d(TAG, "update:onComplete:success"); + promise.resolve(null); + } else { + Log.e(TAG, "update:onComplete:failure", task.getException()); + RNFirebaseFirestore.promiseRejectException( + promise, + (FirebaseFirestoreException) task.getException() + ); + } } - } - }); + }); } /* diff --git a/android/src/main/java/io/invertase/firebase/functions/RNFirebaseFunctions.java b/android/src/main/java/io/invertase/firebase/functions/RNFirebaseFunctions.java index 8b28795b..0f726f72 100644 --- a/android/src/main/java/io/invertase/firebase/functions/RNFirebaseFunctions.java +++ b/android/src/main/java/io/invertase/firebase/functions/RNFirebaseFunctions.java @@ -41,7 +41,10 @@ public class RNFirebaseFunctions extends ReactContextBaseJavaModule { @ReactMethod public void httpsCallable(final String name, ReadableMap wrapper, final Promise promise) { - Object input = wrapper.toHashMap().get(DATA_KEY); + Object input = wrapper + .toHashMap() + .get(DATA_KEY); + Log.d(TAG, "function:call:input:" + name + ":" + (input != null ? input.toString() : "null")); HttpsCallableReference httpsCallableReference = FirebaseFunctions @@ -60,10 +63,14 @@ public class RNFirebaseFunctions extends ReactContextBaseJavaModule { TAG, "function:call:onSuccess:" + name ); + Log.d( TAG, - "function:call:onSuccess:result:type:" + name + ":" + (result != null ? result.getClass().getName() : "null") + "function:call:onSuccess:result:type:" + name + ":" + (result != null ? result + .getClass() + .getName() : "null") ); + Log.d( TAG, "function:call:onSuccess:result:data:" + name + ":" + (result != null ? result.toString() : "null") @@ -71,7 +78,6 @@ public class RNFirebaseFunctions extends ReactContextBaseJavaModule { Utils.mapPutValue(DATA_KEY, result, map); promise.resolve(map); - } }) .addOnFailureListener(new OnFailureListener() { @@ -87,7 +93,9 @@ public class RNFirebaseFunctions extends ReactContextBaseJavaModule { if (exception instanceof FirebaseFunctionsException) { FirebaseFunctionsException ffe = (FirebaseFunctionsException) exception; details = ffe.getDetails(); - code = ffe.getCode().name(); + code = ffe + .getCode() + .name(); message = ffe.getLocalizedMessage(); } else { message = exception.getLocalizedMessage(); diff --git a/android/src/main/java/io/invertase/firebase/instanceid/RNFirebaseInstanceId.java b/android/src/main/java/io/invertase/firebase/instanceid/RNFirebaseInstanceId.java index 7d582e6f..1587862c 100644 --- a/android/src/main/java/io/invertase/firebase/instanceid/RNFirebaseInstanceId.java +++ b/android/src/main/java/io/invertase/firebase/instanceid/RNFirebaseInstanceId.java @@ -1,8 +1,6 @@ package io.invertase.firebase.instanceid; -import java.io.IOException; - import android.util.Log; import com.facebook.react.bridge.Promise; @@ -28,10 +26,12 @@ public class RNFirebaseInstanceId extends ReactContextBaseJavaModule { } @ReactMethod - public void delete(Promise promise){ + public void delete(Promise promise) { try { Log.d(TAG, "Deleting instance id"); - FirebaseInstanceId.getInstance().deleteInstanceId(); + FirebaseInstanceId + .getInstance() + .deleteInstanceId(); promise.resolve(null); } catch (IOException e) { Log.e(TAG, e.getMessage()); @@ -40,15 +40,19 @@ public class RNFirebaseInstanceId extends ReactContextBaseJavaModule { } @ReactMethod - public void get(Promise promise){ - String id = FirebaseInstanceId.getInstance().getId(); + public void get(Promise promise) { + String id = FirebaseInstanceId + .getInstance() + .getId(); promise.resolve(id); } @ReactMethod public void getToken(String authorizedEntity, String scope, Promise promise) { try { - String token = FirebaseInstanceId.getInstance().getToken(authorizedEntity, scope); + String token = FirebaseInstanceId + .getInstance() + .getToken(authorizedEntity, scope); Log.d(TAG, "Firebase token for " + authorizedEntity + ": " + token); promise.resolve(token); } catch (IOException e) { @@ -59,7 +63,9 @@ public class RNFirebaseInstanceId extends ReactContextBaseJavaModule { @ReactMethod public void deleteToken(String authorizedEntity, String scope, Promise promise) { try { - FirebaseInstanceId.getInstance().deleteToken(authorizedEntity, scope); + FirebaseInstanceId + .getInstance() + .deleteToken(authorizedEntity, scope); Log.d(TAG, "Firebase token deleted for " + authorizedEntity); promise.resolve(null); } catch (IOException e) { diff --git a/android/src/main/java/io/invertase/firebase/invites/RNFirebaseInvites.java b/android/src/main/java/io/invertase/firebase/invites/RNFirebaseInvites.java index 1f9b0c83..388417f1 100644 --- a/android/src/main/java/io/invertase/firebase/invites/RNFirebaseInvites.java +++ b/android/src/main/java/io/invertase/firebase/invites/RNFirebaseInvites.java @@ -28,7 +28,6 @@ import java.util.HashMap; import java.util.Map; import io.invertase.firebase.Utils; -import io.invertase.firebase.links.RNFirebaseLinks; public class RNFirebaseInvites extends ReactContextBaseJavaModule implements ActivityEventListener, LifecycleEventListener { private static final String TAG = "RNFirebaseInvites"; @@ -58,21 +57,28 @@ public class RNFirebaseInvites extends ReactContextBaseJavaModule implements Act } } else { if (getCurrentActivity() != null) { - FirebaseDynamicLinks.getInstance() + FirebaseDynamicLinks + .getInstance() .getDynamicLink(getCurrentActivity().getIntent()) .addOnSuccessListener(new OnSuccessListener() { @Override public void onSuccess(PendingDynamicLinkData pendingDynamicLinkData) { if (pendingDynamicLinkData != null) { - FirebaseAppInvite invite = FirebaseAppInvite.getInvitation(pendingDynamicLinkData); + FirebaseAppInvite invite = FirebaseAppInvite.getInvitation( + pendingDynamicLinkData); if (invite == null) { promise.resolve(null); return; } - mInitialDeepLink = pendingDynamicLinkData.getLink().toString(); + mInitialDeepLink = pendingDynamicLinkData + .getLink() + .toString(); mInitialInvitationId = invite.getInvitationId(); - promise.resolve(buildInvitationMap(mInitialDeepLink, mInitialInvitationId)); + promise.resolve(buildInvitationMap( + mInitialDeepLink, + mInitialInvitationId + )); } else { promise.resolve(null); } @@ -83,7 +89,11 @@ public class RNFirebaseInvites extends ReactContextBaseJavaModule implements Act @Override public void onFailure(@NonNull Exception e) { Log.e(TAG, "getInitialInvitation: failed to resolve invitation", e); - promise.reject("invites/initial-invitation-error", e.getMessage(), e); + promise.reject( + "invites/initial-invitation-error", + e.getMessage(), + e + ); } }); } else { @@ -96,15 +106,22 @@ public class RNFirebaseInvites extends ReactContextBaseJavaModule implements Act @ReactMethod public void sendInvitation(ReadableMap invitationMap, Promise promise) { if (!invitationMap.hasKey("message")) { - promise.reject("invites/invalid-invitation", "The supplied invitation is missing a 'message' field"); + promise.reject( + "invites/invalid-invitation", + "The supplied invitation is missing a 'message' field" + ); return; } if (!invitationMap.hasKey("title")) { - promise.reject("invites/invalid-invitation", "The supplied invitation is missing a 'title' field"); + promise.reject( + "invites/invalid-invitation", + "The supplied invitation is missing a 'title' field" + ); return; } - AppInviteInvitation.IntentBuilder ib = new AppInviteInvitation.IntentBuilder(invitationMap.getString("title")); + AppInviteInvitation.IntentBuilder ib = new AppInviteInvitation.IntentBuilder(invitationMap.getString( + "title")); if (invitationMap.hasKey("androidMinimumVersionCode")) { Double androidMinimumVersionCode = invitationMap.getDouble("androidMinimumVersionCode"); ib = ib.setAndroidMinimumVersionCode(androidMinimumVersionCode.intValue()); @@ -121,7 +138,8 @@ public class RNFirebaseInvites extends ReactContextBaseJavaModule implements Act if (invitationMap.hasKey("iosClientId")) { ib = ib.setOtherPlatformsTargetApplication( AppInviteInvitation.IntentBuilder.PlatformMode.PROJECT_PLATFORM_IOS, - invitationMap.getString("iosClientId")); + invitationMap.getString("iosClientId") + ); } ib = ib.setMessage(invitationMap.getString("message")); @@ -155,7 +173,9 @@ public class RNFirebaseInvites extends ReactContextBaseJavaModule implements Act this.mPromise = promise; // Start the intent - this.getCurrentActivity().startActivityForResult(invitationIntent, REQUEST_INVITE); + this + .getCurrentActivity() + .startActivityForResult(invitationIntent, REQUEST_INVITE); } ////////////////////////////////////////////////////////////////////// @@ -179,22 +199,33 @@ public class RNFirebaseInvites extends ReactContextBaseJavaModule implements Act @Override public void onNewIntent(Intent intent) { - FirebaseDynamicLinks.getInstance() + FirebaseDynamicLinks + .getInstance() .getDynamicLink(intent) .addOnSuccessListener(new OnSuccessListener() { @Override public void onSuccess(PendingDynamicLinkData pendingDynamicLinkData) { if (pendingDynamicLinkData != null) { - FirebaseAppInvite invite = FirebaseAppInvite.getInvitation(pendingDynamicLinkData); + FirebaseAppInvite invite = FirebaseAppInvite.getInvitation( + pendingDynamicLinkData); if (invite == null) { // this is a dynamic link, not an invitation return; } - String deepLink = pendingDynamicLinkData.getLink().toString(); + String deepLink = pendingDynamicLinkData + .getLink() + .toString(); String invitationId = invite.getInvitationId(); - WritableMap invitationMap = buildInvitationMap(deepLink, invitationId); - Utils.sendEvent(getReactApplicationContext(), "invites_invitation_received", invitationMap); + WritableMap invitationMap = buildInvitationMap( + deepLink, + invitationId + ); + Utils.sendEvent( + getReactApplicationContext(), + "invites_invitation_received", + invitationMap + ); } } }); diff --git a/android/src/main/java/io/invertase/firebase/links/RNFirebaseLinks.java b/android/src/main/java/io/invertase/firebase/links/RNFirebaseLinks.java index 099bd3d3..6033c84d 100644 --- a/android/src/main/java/io/invertase/firebase/links/RNFirebaseLinks.java +++ b/android/src/main/java/io/invertase/firebase/links/RNFirebaseLinks.java @@ -13,17 +13,15 @@ import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactMethod; import com.facebook.react.bridge.ReadableMap; - +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.Task; import com.google.firebase.appinvite.FirebaseAppInvite; import com.google.firebase.dynamiclinks.DynamicLink; import com.google.firebase.dynamiclinks.FirebaseDynamicLinks; -import com.google.firebase.dynamiclinks.ShortDynamicLink; import com.google.firebase.dynamiclinks.PendingDynamicLinkData; - -import com.google.android.gms.tasks.Task; -import com.google.android.gms.tasks.OnCompleteListener; -import com.google.android.gms.tasks.OnSuccessListener; -import com.google.android.gms.tasks.OnFailureListener; +import com.google.firebase.dynamiclinks.ShortDynamicLink; import io.invertase.firebase.Utils; @@ -47,7 +45,10 @@ public class RNFirebaseLinks extends ReactContextBaseJavaModule implements Activ public void createDynamicLink(final ReadableMap linkData, final Promise promise) { try { DynamicLink.Builder builder = getDynamicLinkBuilder(linkData); - String link = builder.buildDynamicLink().getUri().toString(); + String link = builder + .buildDynamicLink() + .getUri() + .toString(); Log.d(TAG, "created dynamic link: " + link); promise.resolve(link); } catch (Exception ex) { @@ -57,7 +58,11 @@ public class RNFirebaseLinks extends ReactContextBaseJavaModule implements Activ } @ReactMethod - public void createShortDynamicLink(final ReadableMap linkData, final String type, final Promise promise) { + public void createShortDynamicLink( + final ReadableMap linkData, + final String type, + final Promise promise + ) { try { DynamicLink.Builder builder = getDynamicLinkBuilder(linkData); Task shortLinkTask; @@ -70,16 +75,30 @@ public class RNFirebaseLinks extends ReactContextBaseJavaModule implements Activ } shortLinkTask.addOnCompleteListener(new OnCompleteListener() { - @Override - public void onComplete(@NonNull Task task) { - if (task.isSuccessful()) { - String shortLink = task.getResult().getShortLink().toString(); - Log.d(TAG, "created short dynamic link: " + shortLink); - promise.resolve(shortLink); - } else { - Log.e(TAG, "create short dynamic link failure " + task.getException().getMessage()); - promise.reject("links/failure", task.getException().getMessage(), task.getException()); - } + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + String shortLink = task + .getResult() + .getShortLink() + .toString(); + Log.d(TAG, "created short dynamic link: " + shortLink); + promise.resolve(shortLink); + } else { + Log.e( + TAG, + "create short dynamic link failure " + task + .getException() + .getMessage() + ); + promise.reject( + "links/failure", + task + .getException() + .getMessage(), + task.getException() + ); + } } }); } catch (Exception ex) { @@ -94,7 +113,8 @@ public class RNFirebaseLinks extends ReactContextBaseJavaModule implements Activ promise.resolve(mInitialLink); } else { if (getCurrentActivity() != null) { - FirebaseDynamicLinks.getInstance() + FirebaseDynamicLinks + .getInstance() .getDynamicLink(getCurrentActivity().getIntent()) .addOnSuccessListener(new OnSuccessListener() { @Override @@ -102,7 +122,9 @@ public class RNFirebaseLinks extends ReactContextBaseJavaModule implements Activ if (pendingDynamicLinkData != null && !isInvitation(pendingDynamicLinkData)) { - mInitialLink = pendingDynamicLinkData.getLink().toString(); + mInitialLink = pendingDynamicLinkData + .getLink() + .toString(); } Log.d(TAG, "getInitialLink: link is: " + mInitialLink); mInitialLinkInitialized = true; @@ -133,15 +155,22 @@ public class RNFirebaseLinks extends ReactContextBaseJavaModule implements Activ @Override public void onNewIntent(Intent intent) { - FirebaseDynamicLinks.getInstance() + FirebaseDynamicLinks + .getInstance() .getDynamicLink(intent) .addOnSuccessListener(new OnSuccessListener() { @Override public void onSuccess(PendingDynamicLinkData pendingDynamicLinkData) { if (pendingDynamicLinkData != null && !isInvitation(pendingDynamicLinkData)) { - String link = pendingDynamicLinkData.getLink().toString(); - Utils.sendEvent(getReactApplicationContext(), "links_link_received", link); + String link = pendingDynamicLinkData + .getLink() + .toString(); + Utils.sendEvent( + getReactApplicationContext(), + "links_link_received", + link + ); } } }); @@ -175,14 +204,18 @@ public class RNFirebaseLinks extends ReactContextBaseJavaModule implements Activ // Looks at the internals of the link data to detect whether it's an invitation or not private boolean isInvitation(PendingDynamicLinkData pendingDynamicLinkData) { FirebaseAppInvite invite = FirebaseAppInvite.getInvitation(pendingDynamicLinkData); - if (invite != null && invite.getInvitationId() != null && !invite.getInvitationId().isEmpty()) { + if (invite != null && invite.getInvitationId() != null && !invite + .getInvitationId() + .isEmpty()) { return true; } return false; } private DynamicLink.Builder getDynamicLinkBuilder(final ReadableMap linkData) { - DynamicLink.Builder builder = FirebaseDynamicLinks.getInstance().createDynamicLink(); + DynamicLink.Builder builder = FirebaseDynamicLinks + .getInstance() + .createDynamicLink(); try { builder.setLink(Uri.parse(linkData.getString("link"))); builder.setDynamicLinkDomain(linkData.getString("dynamicLinkDomain")); @@ -199,7 +232,10 @@ public class RNFirebaseLinks extends ReactContextBaseJavaModule implements Activ return builder; } - private void setAnalyticsParameters(final ReadableMap analyticsData, final DynamicLink.Builder builder) { + private void setAnalyticsParameters( + final ReadableMap analyticsData, + final DynamicLink.Builder builder + ) { DynamicLink.GoogleAnalyticsParameters.Builder analyticsParameters = new DynamicLink.GoogleAnalyticsParameters.Builder(); if (analyticsData.hasKey("campaign")) { @@ -220,9 +256,13 @@ public class RNFirebaseLinks extends ReactContextBaseJavaModule implements Activ builder.setGoogleAnalyticsParameters(analyticsParameters.build()); } - private void setAndroidParameters(final ReadableMap androidData, final DynamicLink.Builder builder) { + private void setAndroidParameters( + final ReadableMap androidData, + final DynamicLink.Builder builder + ) { if (androidData.hasKey("packageName")) { - DynamicLink.AndroidParameters.Builder androidParameters = new DynamicLink.AndroidParameters.Builder(androidData.getString("packageName")); + DynamicLink.AndroidParameters.Builder androidParameters = new DynamicLink.AndroidParameters.Builder( + androidData.getString("packageName")); if (androidData.hasKey("fallbackUrl")) { androidParameters.setFallbackUrl(Uri.parse(androidData.getString("fallbackUrl"))); @@ -261,7 +301,10 @@ public class RNFirebaseLinks extends ReactContextBaseJavaModule implements Activ } } - private void setITunesParameters(final ReadableMap itunesData, final DynamicLink.Builder builder) { + private void setITunesParameters( + final ReadableMap itunesData, + final DynamicLink.Builder builder + ) { DynamicLink.ItunesConnectAnalyticsParameters.Builder itunesParameters = new DynamicLink.ItunesConnectAnalyticsParameters.Builder(); if (itunesData.hasKey("affiliateToken")) { @@ -276,16 +319,23 @@ public class RNFirebaseLinks extends ReactContextBaseJavaModule implements Activ builder.setItunesConnectAnalyticsParameters(itunesParameters.build()); } - private void setNavigationParameters(final ReadableMap navigationData, final DynamicLink.Builder builder) { + private void setNavigationParameters( + final ReadableMap navigationData, + final DynamicLink.Builder builder + ) { DynamicLink.NavigationInfoParameters.Builder navigationParameters = new DynamicLink.NavigationInfoParameters.Builder(); if (navigationData.hasKey("forcedRedirectEnabled")) { - navigationParameters.setForcedRedirectEnabled(navigationData.getBoolean("forcedRedirectEnabled")); + navigationParameters.setForcedRedirectEnabled(navigationData.getBoolean( + "forcedRedirectEnabled")); } builder.setNavigationInfoParameters(navigationParameters.build()); } - private void setSocialParameters(final ReadableMap socialData, final DynamicLink.Builder builder) { + private void setSocialParameters( + final ReadableMap socialData, + final DynamicLink.Builder builder + ) { DynamicLink.SocialMetaTagParameters.Builder socialParameters = new DynamicLink.SocialMetaTagParameters.Builder(); if (socialData.hasKey("descriptionText")) { diff --git a/android/src/main/java/io/invertase/firebase/links/RNFirebaseLinksPackage.java b/android/src/main/java/io/invertase/firebase/links/RNFirebaseLinksPackage.java index ad8b6f42..bb068466 100644 --- a/android/src/main/java/io/invertase/firebase/links/RNFirebaseLinksPackage.java +++ b/android/src/main/java/io/invertase/firebase/links/RNFirebaseLinksPackage.java @@ -1,7 +1,6 @@ package io.invertase.firebase.links; import com.facebook.react.ReactPackage; -import com.facebook.react.bridge.JavaScriptModule; import com.facebook.react.bridge.NativeModule; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.uimanager.UIManagerModule; diff --git a/android/src/main/java/io/invertase/firebase/messaging/BundleJSONConverter.java b/android/src/main/java/io/invertase/firebase/messaging/BundleJSONConverter.java index 72b3fa13..56a4c2d6 100644 --- a/android/src/main/java/io/invertase/firebase/messaging/BundleJSONConverter.java +++ b/android/src/main/java/io/invertase/firebase/messaging/BundleJSONConverter.java @@ -39,9 +39,9 @@ import java.util.Map; * com.facebook.internal is solely for the use of other packages within the Facebook SDK for * Android. Use of any of the classes in this package is unsupported, and they may be modified or * removed without warning at any time. - * + *

* A helper class that can round trip between JSON and Bundle objects that contains the types: - * Boolean, Integer, Long, Double, String + * Boolean, Integer, Long, Double, String * If other types are found, an IllegalArgumentException is thrown. */ public class BundleJSONConverter { @@ -126,13 +126,13 @@ public class BundleJSONConverter { } else if (jsonArray.get(0) instanceof Boolean) { boolean[] booleanArray = new boolean[jsonArray.length()]; for (int i = 0; i < jsonArray.length(); i++) { - booleanArray[i] = (Boolean)jsonArray.get(i); + booleanArray[i] = (Boolean) jsonArray.get(i); } bundle.putBooleanArray(key, booleanArray); } else if (jsonArray.get(0) instanceof Double) { double[] doubleArray = new double[jsonArray.length()]; for (int i = 0; i < jsonArray.length(); i++) { - doubleArray[i] = (Double)jsonArray.get(i); + doubleArray[i] = (Double) jsonArray.get(i); } bundle.putDoubleArray(key, doubleArray); } else if (jsonArray.get(0) instanceof Long) { @@ -143,12 +143,14 @@ public class BundleJSONConverter { bundle.putLongArray(key, longArray); } else if (jsonArray.get(0) instanceof JSONObject) { ArrayList bundleArrayList = new ArrayList<>(); - for (int i =0; i < jsonArray.length(); i++) { + for (int i = 0; i < jsonArray.length(); i++) { bundleArrayList.add(convertToBundle((JSONObject) jsonArray.get(i))); } bundle.putSerializable(key, bundleArrayList); } else { - throw new IllegalArgumentException("Unexpected type in an array: " + jsonArray.get(0).getClass()); + throw new IllegalArgumentException("Unexpected type in an array: " + jsonArray + .get(0) + .getClass()); } } @@ -159,12 +161,6 @@ public class BundleJSONConverter { }); } - public interface Setter { - public void setOnBundle(Bundle bundle, String key, Object value) throws JSONException; - - public void setOnJSON(JSONObject json, String key, Object value) throws JSONException; - } - public static JSONObject convertToJSON(Bundle bundle) throws JSONException { JSONObject json = new JSONObject(); @@ -239,4 +235,10 @@ public class BundleJSONConverter { return bundle; } + + public interface Setter { + public void setOnBundle(Bundle bundle, String key, Object value) throws JSONException; + + public void setOnJSON(JSONObject json, String key, Object value) throws JSONException; + } } diff --git a/android/src/main/java/io/invertase/firebase/messaging/MessagingSerializer.java b/android/src/main/java/io/invertase/firebase/messaging/MessagingSerializer.java index 2bba2ec0..12df03c3 100644 --- a/android/src/main/java/io/invertase/firebase/messaging/MessagingSerializer.java +++ b/android/src/main/java/io/invertase/firebase/messaging/MessagingSerializer.java @@ -6,7 +6,6 @@ import com.google.firebase.messaging.RemoteMessage; import java.util.Map; - public class MessagingSerializer { public static WritableMap parseRemoteMessage(RemoteMessage message) { WritableMap messageMap = Arguments.createMap(); @@ -17,7 +16,9 @@ public class MessagingSerializer { } if (message.getData() != null) { - for (Map.Entry e : message.getData().entrySet()) { + for (Map.Entry e : message + .getData() + .entrySet()) { dataMap.putString(e.getKey(), e.getValue()); } } diff --git a/android/src/main/java/io/invertase/firebase/messaging/RNFirebaseBackgroundMessagingService.java b/android/src/main/java/io/invertase/firebase/messaging/RNFirebaseBackgroundMessagingService.java index b0a0b046..1e0f69c4 100644 --- a/android/src/main/java/io/invertase/firebase/messaging/RNFirebaseBackgroundMessagingService.java +++ b/android/src/main/java/io/invertase/firebase/messaging/RNFirebaseBackgroundMessagingService.java @@ -4,7 +4,6 @@ import android.content.Intent; import android.os.Bundle; import com.facebook.react.HeadlessJsTaskService; -import com.facebook.react.bridge.Arguments; import com.facebook.react.bridge.WritableMap; import com.facebook.react.jstasks.HeadlessJsTaskConfig; import com.google.firebase.messaging.RemoteMessage; @@ -13,7 +12,8 @@ import javax.annotation.Nullable; public class RNFirebaseBackgroundMessagingService extends HeadlessJsTaskService { @Override - protected @Nullable HeadlessJsTaskConfig getTaskConfig(Intent intent) { + protected @Nullable + HeadlessJsTaskConfig getTaskConfig(Intent intent) { Bundle extras = intent.getExtras(); if (extras != null) { RemoteMessage message = intent.getParcelableExtra("message"); diff --git a/android/src/main/java/io/invertase/firebase/messaging/RNFirebaseInstanceIdService.java b/android/src/main/java/io/invertase/firebase/messaging/RNFirebaseInstanceIdService.java index 349760f4..98f20816 100644 --- a/android/src/main/java/io/invertase/firebase/messaging/RNFirebaseInstanceIdService.java +++ b/android/src/main/java/io/invertase/firebase/messaging/RNFirebaseInstanceIdService.java @@ -1,6 +1,5 @@ package io.invertase.firebase.messaging; - import android.content.Intent; import android.support.v4.content.LocalBroadcastManager; import android.util.Log; @@ -8,8 +7,8 @@ import android.util.Log; import com.google.firebase.iid.FirebaseInstanceIdService; public class RNFirebaseInstanceIdService extends FirebaseInstanceIdService { - private static final String TAG = "RNFInstanceIdService"; public static final String TOKEN_REFRESH_EVENT = "messaging-token-refresh"; + private static final String TAG = "RNFInstanceIdService"; @Override public void onTokenRefresh() { @@ -19,6 +18,8 @@ public class RNFirebaseInstanceIdService extends FirebaseInstanceIdService { Intent tokenRefreshEvent = new Intent(TOKEN_REFRESH_EVENT); // Broadcast it so it is only available to the RN Application - LocalBroadcastManager.getInstance(this).sendBroadcast(tokenRefreshEvent); + LocalBroadcastManager + .getInstance(this) + .sendBroadcast(tokenRefreshEvent); } } diff --git a/android/src/main/java/io/invertase/firebase/messaging/RNFirebaseMessaging.java b/android/src/main/java/io/invertase/firebase/messaging/RNFirebaseMessaging.java index 3bc702bb..9573b270 100644 --- a/android/src/main/java/io/invertase/firebase/messaging/RNFirebaseMessaging.java +++ b/android/src/main/java/io/invertase/firebase/messaging/RNFirebaseMessaging.java @@ -5,8 +5,8 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.support.annotation.NonNull; -import android.support.v4.content.LocalBroadcastManager; import android.support.v4.app.NotificationManagerCompat; +import android.support.v4.content.LocalBroadcastManager; import android.util.Log; import com.facebook.react.bridge.Promise; @@ -32,12 +32,16 @@ public class RNFirebaseMessaging extends ReactContextBaseJavaModule { LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(context); // Subscribe to message events - localBroadcastManager.registerReceiver(new MessageReceiver(), - new IntentFilter(RNFirebaseMessagingService.MESSAGE_EVENT)); + localBroadcastManager.registerReceiver( + new MessageReceiver(), + new IntentFilter(RNFirebaseMessagingService.MESSAGE_EVENT) + ); // Subscribe to token refresh events - localBroadcastManager.registerReceiver(new RefreshTokenReceiver(), - new IntentFilter(RNFirebaseInstanceIdService.TOKEN_REFRESH_EVENT)); + localBroadcastManager.registerReceiver( + new RefreshTokenReceiver(), + new IntentFilter(RNFirebaseInstanceIdService.TOKEN_REFRESH_EVENT) + ); } @Override @@ -47,7 +51,9 @@ public class RNFirebaseMessaging extends ReactContextBaseJavaModule { @ReactMethod public void getToken(Promise promise) { - String token = FirebaseInstanceId.getInstance().getToken(); + String token = FirebaseInstanceId + .getInstance() + .getToken(); Log.d(TAG, "Firebase token: " + token); promise.resolve(token); } @@ -60,7 +66,9 @@ public class RNFirebaseMessaging extends ReactContextBaseJavaModule { // Non Web SDK methods @ReactMethod public void hasPermission(Promise promise) { - Boolean enabled = NotificationManagerCompat.from(getReactApplicationContext()).areNotificationsEnabled(); + Boolean enabled = NotificationManagerCompat + .from(getReactApplicationContext()) + .areNotificationsEnabled(); promise.resolve(enabled); } @@ -94,7 +102,9 @@ public class RNFirebaseMessaging extends ReactContextBaseJavaModule { } } - FirebaseMessaging.getInstance().send(mb.build()); + FirebaseMessaging + .getInstance() + .send(mb.build()); // TODO: Listen to onMessageSent and onSendError for better feedback? promise.resolve(null); @@ -102,36 +112,42 @@ public class RNFirebaseMessaging extends ReactContextBaseJavaModule { @ReactMethod public void subscribeToTopic(String topic, final Promise promise) { - FirebaseMessaging.getInstance().subscribeToTopic(topic).addOnCompleteListener(new OnCompleteListener() { - @Override - public void onComplete(@NonNull Task task) { - if (task.isSuccessful()) { - Log.d(TAG, "subscribeToTopic:onComplete:success"); - promise.resolve(null); - } else { - Exception exception = task.getException(); - Log.e(TAG, "subscribeToTopic:onComplete:failure", exception); - promise.reject(exception); + FirebaseMessaging + .getInstance() + .subscribeToTopic(topic) + .addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + Log.d(TAG, "subscribeToTopic:onComplete:success"); + promise.resolve(null); + } else { + Exception exception = task.getException(); + Log.e(TAG, "subscribeToTopic:onComplete:failure", exception); + promise.reject(exception); + } } - } - }); + }); } @ReactMethod public void unsubscribeFromTopic(String topic, final Promise promise) { - FirebaseMessaging.getInstance().unsubscribeFromTopic(topic).addOnCompleteListener(new OnCompleteListener() { - @Override - public void onComplete(@NonNull Task task) { - if (task.isSuccessful()) { - Log.d(TAG, "unsubscribeFromTopic:onComplete:success"); - promise.resolve(null); - } else { - Exception exception = task.getException(); - Log.e(TAG, "unsubscribeFromTopic:onComplete:failure", exception); - promise.reject(exception); + FirebaseMessaging + .getInstance() + .unsubscribeFromTopic(topic) + .addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + Log.d(TAG, "unsubscribeFromTopic:onComplete:success"); + promise.resolve(null); + } else { + Exception exception = task.getException(); + Log.e(TAG, "unsubscribeFromTopic:onComplete:failure", exception); + promise.reject(exception); + } } - } - }); + }); } private class MessageReceiver extends BroadcastReceiver { @@ -152,7 +168,9 @@ public class RNFirebaseMessaging extends ReactContextBaseJavaModule { @Override public void onReceive(Context context, Intent intent) { if (getReactApplicationContext().hasActiveCatalystInstance()) { - String token = FirebaseInstanceId.getInstance().getToken(); + String token = FirebaseInstanceId + .getInstance() + .getToken(); Log.d(TAG, "Received new FCM token: " + token); Utils.sendEvent(getReactApplicationContext(), "messaging_token_refreshed", token); diff --git a/android/src/main/java/io/invertase/firebase/messaging/RNFirebaseMessagingService.java b/android/src/main/java/io/invertase/firebase/messaging/RNFirebaseMessagingService.java index 906c9e85..b9e8ba7f 100644 --- a/android/src/main/java/io/invertase/firebase/messaging/RNFirebaseMessagingService.java +++ b/android/src/main/java/io/invertase/firebase/messaging/RNFirebaseMessagingService.java @@ -11,9 +11,9 @@ import com.google.firebase.messaging.RemoteMessage; import io.invertase.firebase.Utils; public class RNFirebaseMessagingService extends FirebaseMessagingService { - private static final String TAG = "RNFMessagingService"; public static final String MESSAGE_EVENT = "messaging-message"; public static final String REMOTE_NOTIFICATION_EVENT = "notifications-remote-notification"; + private static final String TAG = "RNFMessagingService"; @Override public void onMessageReceived(RemoteMessage message) { @@ -25,7 +25,9 @@ public class RNFirebaseMessagingService extends FirebaseMessagingService { notificationEvent.putExtra("notification", message); // Broadcast it to the (foreground) RN Application - LocalBroadcastManager.getInstance(this).sendBroadcast(notificationEvent); + LocalBroadcastManager + .getInstance(this) + .sendBroadcast(notificationEvent); } else { // It's a data message // If the app is in the foreground we send it to the Messaging module @@ -33,16 +35,27 @@ public class RNFirebaseMessagingService extends FirebaseMessagingService { Intent messagingEvent = new Intent(MESSAGE_EVENT); messagingEvent.putExtra("message", message); // Broadcast it so it is only available to the RN Application - LocalBroadcastManager.getInstance(this).sendBroadcast(messagingEvent); + LocalBroadcastManager + .getInstance(this) + .sendBroadcast(messagingEvent); } else { try { // If the app is in the background we send it to the Headless JS Service - Intent headlessIntent = new Intent(this.getApplicationContext(), RNFirebaseBackgroundMessagingService.class); + Intent headlessIntent = new Intent( + this.getApplicationContext(), + RNFirebaseBackgroundMessagingService.class + ); headlessIntent.putExtra("message", message); - this.getApplicationContext().startService(headlessIntent); + this + .getApplicationContext() + .startService(headlessIntent); HeadlessJsTaskService.acquireWakeLockNow(this.getApplicationContext()); } catch (IllegalStateException ex) { - Log.e(TAG, "Background messages will only work if the message priority is set to 'high'", ex); + Log.e( + TAG, + "Background messages will only work if the message priority is set to 'high'", + ex + ); } } } diff --git a/android/src/main/java/io/invertase/firebase/notifications/DisplayNotificationTask.java b/android/src/main/java/io/invertase/firebase/notifications/DisplayNotificationTask.java index c1cebe80..4db3da15 100644 --- a/android/src/main/java/io/invertase/firebase/notifications/DisplayNotificationTask.java +++ b/android/src/main/java/io/invertase/firebase/notifications/DisplayNotificationTask.java @@ -37,9 +37,11 @@ public class DisplayNotificationTask extends AsyncTask { private final Promise promise; private ReactApplicationContext reactContext; - public DisplayNotificationTask(Context context, ReactApplicationContext reactContext, - NotificationManager notificationManager, - Bundle notification, Promise promise) { + public DisplayNotificationTask( + Context context, ReactApplicationContext reactContext, + NotificationManager notificationManager, + Bundle notification, Promise promise + ) { this.context = context; this.notification = notification; this.notificationManager = notificationManager; @@ -53,7 +55,10 @@ public class DisplayNotificationTask extends AsyncTask { Class intentClass = getMainActivityClass(); if (intentClass == null) { if (promise != null) { - promise.reject("notification/display_notification_error", "Could not find main activity class"); + promise.reject( + "notification/display_notification_error", + "Could not find main activity class" + ); } return null; } @@ -77,7 +82,10 @@ public class DisplayNotificationTask extends AsyncTask { nb = nb.setExtras(notification.getBundle("data")); } if (notification.containsKey("sound")) { - Uri sound = RNFirebaseNotificationManager.getSound(context, notification.getString("sound")); + Uri sound = RNFirebaseNotificationManager.getSound( + context, + notification.getString("sound") + ); nb = nb.setSound(sound); } if (notification.containsKey("subtitle")) { @@ -148,7 +156,7 @@ public class DisplayNotificationTask extends AsyncTask { if (defaults == 0) { ArrayList defaultsArray = android.getIntegerArrayList("defaults"); - if(defaultsArray != null) { + if (defaultsArray != null) { for (Integer defaultValue : defaultsArray) { defaults |= defaultValue; } @@ -210,7 +218,11 @@ public class DisplayNotificationTask extends AsyncTask { Bundle progress = android.getBundle("progress"); Double max = progress.getDouble("max"); Double progressI = progress.getDouble("progress"); - nb = nb.setProgress(max.intValue(), progressI.intValue(), progress.getBoolean("indeterminate")); + nb = nb.setProgress( + max.intValue(), + progressI.intValue(), + progress.getBoolean("indeterminate") + ); } // TODO: Public version of notification /* if (android.containsKey("publicVersion")) { @@ -253,10 +265,12 @@ public class DisplayNotificationTask extends AsyncTask { } if (android.containsKey("vibrate")) { ArrayList vibrate = android.getIntegerArrayList("vibrate"); - if(vibrate != null) { + if (vibrate != null) { long[] vibrateArray = new long[vibrate.size()]; for (int i = 0; i < vibrate.size(); i++) { - vibrateArray[i] = vibrate.get(i).longValue(); + vibrateArray[i] = vibrate + .get(i) + .longValue(); } nb = nb.setVibrate(vibrateArray); } @@ -281,11 +295,15 @@ public class DisplayNotificationTask extends AsyncTask { String tag = null; if (android.containsKey("tag")) { - tag = android.getString("tag"); + tag = android.getString("tag"); } // Create the notification intent - PendingIntent contentIntent = createIntent(intentClass, notification, android.getString("clickAction")); + PendingIntent contentIntent = createIntent( + intentClass, + notification, + android.getString("clickAction") + ); nb = nb.setContentIntent(contentIntent); // Build the notification and send it @@ -293,7 +311,11 @@ public class DisplayNotificationTask extends AsyncTask { notificationManager.notify(tag, notificationId.hashCode(), builtNotification); if (reactContext != null) { - Utils.sendEvent(reactContext, "notifications_notification_displayed", Arguments.fromBundle(notification)); + Utils.sendEvent( + reactContext, + "notifications_notification_displayed", + Arguments.fromBundle(notification) + ); } if (promise != null) { @@ -310,8 +332,13 @@ public class DisplayNotificationTask extends AsyncTask { return null; } - private NotificationCompat.Action createAction(Bundle action, Class intentClass, Bundle notification) { - boolean showUserInterface = action.containsKey("showUserInterface") && action.getBoolean("showUserInterface"); + private NotificationCompat.Action createAction( + Bundle action, + Class intentClass, + Bundle notification + ) { + boolean showUserInterface = action.containsKey("showUserInterface") && action.getBoolean( + "showUserInterface"); String actionKey = action.getString("action"); PendingIntent actionIntent = showUserInterface ? createIntent(intentClass, notification, actionKey) : @@ -319,7 +346,11 @@ public class DisplayNotificationTask extends AsyncTask { int icon = getIcon(action.getString("icon")); String title = action.getString("title"); - NotificationCompat.Action.Builder ab = new NotificationCompat.Action.Builder(icon, title, actionIntent); + NotificationCompat.Action.Builder ab = new NotificationCompat.Action.Builder( + icon, + title, + actionIntent + ); if (action.containsKey("allowGeneratedReplies")) { ab = ab.setAllowGeneratedReplies(action.getBoolean("allowGeneratedReplies")); @@ -353,7 +384,12 @@ public class DisplayNotificationTask extends AsyncTask { } String notificationId = notification.getString("notificationId"); - return PendingIntent.getActivity(context, notificationId.hashCode(), intent, PendingIntent.FLAG_UPDATE_CURRENT); + return PendingIntent.getActivity( + context, + notificationId.hashCode(), + intent, + PendingIntent.FLAG_UPDATE_CURRENT + ); } private PendingIntent createBroadcastIntent(Bundle notification, String action) { @@ -365,7 +401,12 @@ public class DisplayNotificationTask extends AsyncTask { intent.setAction("io.invertase.firebase.notifications.BackgroundAction"); intent.putExtra("action", action); intent.putExtra("notification", notification); - return PendingIntent.getBroadcast(context, notificationId.hashCode(), intent, PendingIntent.FLAG_UPDATE_CURRENT); + return PendingIntent.getBroadcast( + context, + notificationId.hashCode(), + intent, + PendingIntent.FLAG_UPDATE_CURRENT + ); } private RemoteInput createRemoteInput(Bundle remoteInput) { @@ -417,18 +458,22 @@ public class DisplayNotificationTask extends AsyncTask { } private int getIcon(String icon) { - int resourceId = RNFirebaseNotificationManager.getResourceId(context,"mipmap", icon); + int resourceId = RNFirebaseNotificationManager.getResourceId(context, "mipmap", icon); if (resourceId == 0) { - resourceId = RNFirebaseNotificationManager.getResourceId(context,"drawable", icon); + resourceId = RNFirebaseNotificationManager.getResourceId(context, "drawable", icon); } return resourceId; } private Class getMainActivityClass() { String packageName = context.getPackageName(); - Intent launchIntent = context.getPackageManager().getLaunchIntentForPackage(packageName); + Intent launchIntent = context + .getPackageManager() + .getLaunchIntentForPackage(packageName); try { - return Class.forName(launchIntent.getComponent().getClassName()); + return Class.forName(launchIntent + .getComponent() + .getClassName()); } catch (ClassNotFoundException e) { Log.e(TAG, "Failed to get main activity class", e); return null; diff --git a/android/src/main/java/io/invertase/firebase/notifications/RNFirebaseBackgroundNotificationActionReceiver.java b/android/src/main/java/io/invertase/firebase/notifications/RNFirebaseBackgroundNotificationActionReceiver.java index 4ac2db87..6ca24ed4 100644 --- a/android/src/main/java/io/invertase/firebase/notifications/RNFirebaseBackgroundNotificationActionReceiver.java +++ b/android/src/main/java/io/invertase/firebase/notifications/RNFirebaseBackgroundNotificationActionReceiver.java @@ -36,12 +36,18 @@ public class RNFirebaseBackgroundNotificationActionReceiver extends BroadcastRec if (Utils.isAppInForeground(context)) { WritableMap notificationOpenMap = toNotificationOpenMap(intent); - ReactApplication reactApplication = (ReactApplication)context.getApplicationContext(); - ReactContext reactContext = reactApplication.getReactNativeHost().getReactInstanceManager().getCurrentReactContext(); + ReactApplication reactApplication = (ReactApplication) context.getApplicationContext(); + ReactContext reactContext = reactApplication + .getReactNativeHost() + .getReactInstanceManager() + .getCurrentReactContext(); Utils.sendEvent(reactContext, "notifications_notification_opened", notificationOpenMap); } else { - Intent serviceIntent = new Intent(context, RNFirebaseBackgroundNotificationActionsService.class); + Intent serviceIntent = new Intent( + context, + RNFirebaseBackgroundNotificationActionsService.class + ); serviceIntent.putExtras(intent.getExtras()); context.startService(serviceIntent); HeadlessJsTaskService.acquireWakeLockNow(context); diff --git a/android/src/main/java/io/invertase/firebase/notifications/RNFirebaseBackgroundNotificationActionsService.java b/android/src/main/java/io/invertase/firebase/notifications/RNFirebaseBackgroundNotificationActionsService.java index 9bfb83bb..56f702d4 100644 --- a/android/src/main/java/io/invertase/firebase/notifications/RNFirebaseBackgroundNotificationActionsService.java +++ b/android/src/main/java/io/invertase/firebase/notifications/RNFirebaseBackgroundNotificationActionsService.java @@ -13,7 +13,8 @@ import static io.invertase.firebase.notifications.RNFirebaseBackgroundNotificati public class RNFirebaseBackgroundNotificationActionsService extends HeadlessJsTaskService { @Override - protected @Nullable HeadlessJsTaskConfig getTaskConfig(Intent intent) { + protected @Nullable + HeadlessJsTaskConfig getTaskConfig(Intent intent) { if (isBackgroundNotficationIntent(intent)) { WritableMap notificationOpenMap = toNotificationOpenMap(intent); diff --git a/android/src/main/java/io/invertase/firebase/notifications/RNFirebaseNotificationManager.java b/android/src/main/java/io/invertase/firebase/notifications/RNFirebaseNotificationManager.java index f347306d..85de6a93 100644 --- a/android/src/main/java/io/invertase/firebase/notifications/RNFirebaseNotificationManager.java +++ b/android/src/main/java/io/invertase/firebase/notifications/RNFirebaseNotificationManager.java @@ -2,7 +2,6 @@ package io.invertase.firebase.notifications; import android.app.AlarmManager; -import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationChannelGroup; import android.app.NotificationManager; @@ -10,8 +9,6 @@ import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; import android.graphics.Color; import android.media.RingtoneManager; import android.net.Uri; @@ -19,8 +16,6 @@ import android.os.Build; import android.os.Bundle; import android.service.notification.StatusBarNotification; import android.support.annotation.Nullable; -import android.support.v4.app.NotificationCompat; -import android.support.v4.app.RemoteInput; import android.support.v4.content.LocalBroadcastManager; import android.util.Log; @@ -33,9 +28,6 @@ import com.facebook.react.bridge.ReadableMap; import org.json.JSONException; import org.json.JSONObject; -import java.io.IOException; -import java.net.HttpURLConnection; -import java.net.URL; import java.util.ArrayList; import java.util.Calendar; import java.util.List; @@ -45,8 +37,8 @@ import io.invertase.firebase.Utils; import io.invertase.firebase.messaging.BundleJSONConverter; public class RNFirebaseNotificationManager { - private static final String PREFERENCES_KEY = "RNFNotifications"; public static final String SCHEDULED_NOTIFICATION_EVENT = "notifications-scheduled-notification"; + private static final String PREFERENCES_KEY = "RNFNotifications"; private static final String TAG = "RNFNotificationManager"; private AlarmManager alarmManager; private Context context; @@ -62,31 +54,63 @@ public class RNFirebaseNotificationManager { public RNFirebaseNotificationManager(Context context) { this.alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); this.context = context; - this.notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + this.notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); this.preferences = context.getSharedPreferences(PREFERENCES_KEY, Context.MODE_PRIVATE); } + public static int getResourceId(Context context, String type, String image) { + return context + .getResources() + .getIdentifier(image, type, context.getPackageName()); + } + + public static Uri getSound(Context context, String sound) { + if (sound == null) { + return null; + } else if (sound.contains("://")) { + return Uri.parse(sound); + } else if (sound.equalsIgnoreCase("default")) { + return RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); + } else { + int soundResourceId = getResourceId(context, "raw", sound); + if (soundResourceId == 0) { + soundResourceId = getResourceId(context, "raw", sound.substring(0, sound.lastIndexOf('.'))); + } + return Uri.parse("android.resource://" + context.getPackageName() + "/" + soundResourceId); + } + } + public void cancelAllNotifications(Promise promise) { try { Map notifications = preferences.getAll(); - for(String notificationId : notifications.keySet()){ + for (String notificationId : notifications.keySet()) { cancelAlarm(notificationId); } - preferences.edit().clear().apply(); + preferences + .edit() + .clear() + .apply(); promise.resolve(null); } catch (SecurityException e) { // TODO: Identify what these situations are // In some devices/situations cancelAllLocalNotifications can throw a SecurityException. Log.e(TAG, e.getMessage()); - promise.reject("notification/cancel_notifications_error", "Could not cancel notifications", e); + promise.reject( + "notification/cancel_notifications_error", + "Could not cancel notifications", + e + ); } } public void cancelNotification(String notificationId, Promise promise) { try { cancelAlarm(notificationId); - preferences.edit().remove(notificationId).apply(); + preferences + .edit() + .remove(notificationId) + .apply(); promise.resolve(null); } catch (SecurityException e) { // TODO: Identify what these situations are @@ -151,10 +175,17 @@ public class RNFirebaseNotificationManager { public void displayScheduledNotification(Bundle notification) { // If this isn't a repeated notification, clear it from the scheduled notifications list - if (!notification.getBundle("schedule").containsKey("repeated") - || !notification.getBundle("schedule").getBoolean("repeated")) { + if (!notification + .getBundle("schedule") + .containsKey("repeated") + || !notification + .getBundle("schedule") + .getBoolean("repeated")) { String notificationId = notification.getString("notificationId"); - preferences.edit().remove(notificationId).apply(); + preferences + .edit() + .remove(notificationId) + .apply(); } if (Utils.isAppInForeground(context)) { @@ -162,21 +193,23 @@ public class RNFirebaseNotificationManager { // It is up to the JS to decide whether to display the notification Intent scheduledNotificationEvent = new Intent(SCHEDULED_NOTIFICATION_EVENT); scheduledNotificationEvent.putExtra("notification", notification); - LocalBroadcastManager.getInstance(context).sendBroadcast(scheduledNotificationEvent); + LocalBroadcastManager + .getInstance(context) + .sendBroadcast(scheduledNotificationEvent); } else { // If the app is in the background, then we display it automatically displayNotification(notification, null); } } - public ArrayList getScheduledNotifications(){ + public ArrayList getScheduledNotifications() { ArrayList array = new ArrayList<>(); Map notifications = preferences.getAll(); - for(String notificationId : notifications.keySet()){ + for (String notificationId : notifications.keySet()) { try { - JSONObject json = new JSONObject((String)notifications.get(notificationId)); + JSONObject json = new JSONObject((String) notifications.get(notificationId)); Bundle bundle = BundleJSONConverter.convertToBundle(json); array.add(bundle); } catch (JSONException e) { @@ -199,16 +232,16 @@ public class RNFirebaseNotificationManager { public void removeDeliveredNotificationsByTag(String tag, Promise promise) { StatusBarNotification[] statusBarNotifications = notificationManager.getActiveNotifications(); for (StatusBarNotification statusBarNotification : statusBarNotifications) { - if (statusBarNotification.getTag() == tag) { - notificationManager.cancel(statusBarNotification.getTag(), statusBarNotification.getId()); - } + if (statusBarNotification.getTag() == tag) { + notificationManager.cancel(statusBarNotification.getTag(), statusBarNotification.getId()); + } } promise.resolve(null); } public void rescheduleNotifications() { ArrayList bundles = getScheduledNotifications(); - for(Bundle bundle: bundles){ + for (Bundle bundle : bundles) { scheduleNotification(bundle, null); } } @@ -221,32 +254,23 @@ public class RNFirebaseNotificationManager { private void cancelAlarm(String notificationId) { Intent notificationIntent = new Intent(context, RNFirebaseNotificationReceiver.class); - PendingIntent pendingIntent = PendingIntent.getBroadcast(context, notificationId.hashCode(), notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT); + PendingIntent pendingIntent = PendingIntent.getBroadcast( + context, + notificationId.hashCode(), + notificationIntent, + PendingIntent.FLAG_UPDATE_CURRENT + ); alarmManager.cancel(pendingIntent); } private void displayNotification(Bundle notification, Promise promise) { - new DisplayNotificationTask(context, reactContext, notificationManager, notification, promise).execute(); - } - - public static int getResourceId(Context context, String type, String image) { - return context.getResources().getIdentifier(image, type, context.getPackageName()); - } - - public static Uri getSound(Context context, String sound) { - if (sound == null) { - return null; - } else if (sound.contains("://")) { - return Uri.parse(sound); - } else if (sound.equalsIgnoreCase("default")) { - return RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); - } else { - int soundResourceId = getResourceId(context,"raw", sound); - if (soundResourceId == 0) { - soundResourceId = getResourceId(context,"raw", sound.substring(0, sound.lastIndexOf('.'))); - } - return Uri.parse("android.resource://" + context.getPackageName() + "/" + soundResourceId); - } + new DisplayNotificationTask( + context, + reactContext, + notificationManager, + notification, + promise + ).execute(); } private NotificationChannelGroup parseChannelGroupMap(ReadableMap channelGroupMap) { @@ -356,20 +380,31 @@ public class RNFirebaseNotificationManager { // We store them so that they can be re-scheduled when the phone restarts in RNFirebaseNotificationsRebootReceiver try { JSONObject json = BundleJSONConverter.convertToJSON(notification); - preferences.edit().putString(notificationId, json.toString()).apply(); + preferences + .edit() + .putString(notificationId, json.toString()) + .apply(); } catch (JSONException e) { if (promise == null) { Log.e(TAG, "Failed to store notification"); } else { - promise.reject("notification/schedule_notification_error", "Failed to store notification", e); + promise.reject( + "notification/schedule_notification_error", + "Failed to store notification", + e + ); } return; } Intent notificationIntent = new Intent(context, RNFirebaseNotificationReceiver.class); notificationIntent.putExtras(notification); - PendingIntent pendingIntent = PendingIntent.getBroadcast(context, notificationId.hashCode(), - notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT); + PendingIntent pendingIntent = PendingIntent.getBroadcast( + context, + notificationId.hashCode(), + notificationIntent, + PendingIntent.FLAG_UPDATE_CURRENT + ); if (schedule.containsKey("repeatInterval")) { // If fireDate you specify is in the past, the alarm triggers immediately. diff --git a/android/src/main/java/io/invertase/firebase/notifications/RNFirebaseNotifications.java b/android/src/main/java/io/invertase/firebase/notifications/RNFirebaseNotifications.java index 58f7a3de..253d63da 100644 --- a/android/src/main/java/io/invertase/firebase/notifications/RNFirebaseNotifications.java +++ b/android/src/main/java/io/invertase/firebase/notifications/RNFirebaseNotifications.java @@ -41,6 +41,7 @@ public class RNFirebaseNotifications extends ReactContextBaseJavaModule implemen private SharedPreferences sharedPreferences = null; private RNFirebaseNotificationManager notificationManager; + public RNFirebaseNotifications(ReactApplicationContext context) { super(context); context.addActivityEventListener(this); @@ -51,12 +52,16 @@ public class RNFirebaseNotifications extends ReactContextBaseJavaModule implemen LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(context); // Subscribe to remote notification events - localBroadcastManager.registerReceiver(new RemoteNotificationReceiver(), - new IntentFilter(RNFirebaseMessagingService.REMOTE_NOTIFICATION_EVENT)); + localBroadcastManager.registerReceiver( + new RemoteNotificationReceiver(), + new IntentFilter(RNFirebaseMessagingService.REMOTE_NOTIFICATION_EVENT) + ); // Subscribe to scheduled notification events - localBroadcastManager.registerReceiver(new ScheduledNotificationReceiver(), - new IntentFilter(RNFirebaseNotificationManager.SCHEDULED_NOTIFICATION_EVENT)); + localBroadcastManager.registerReceiver( + new ScheduledNotificationReceiver(), + new IntentFilter(RNFirebaseNotificationManager.SCHEDULED_NOTIFICATION_EVENT) + ); } @Override @@ -123,7 +128,10 @@ public class RNFirebaseNotifications extends ReactContextBaseJavaModule implemen @ReactMethod public void setBadge(int badge, Promise promise) { // Store the badge count for later retrieval - sharedPreferences.edit().putInt(BADGE_KEY, badge).apply(); + sharedPreferences + .edit() + .putInt(BADGE_KEY, badge) + .apply(); if (badge == 0) { Log.d(TAG, "Remove badge count"); ShortcutBadger.removeCount(this.getReactApplicationContext()); @@ -193,7 +201,11 @@ public class RNFirebaseNotifications extends ReactContextBaseJavaModule implemen public void onNewIntent(Intent intent) { WritableMap notificationOpenMap = parseIntentForNotification(intent); if (notificationOpenMap != null) { - Utils.sendEvent(getReactApplicationContext(), "notifications_notification_opened", notificationOpenMap); + Utils.sendEvent( + getReactApplicationContext(), + "notifications_notification_opened", + notificationOpenMap + ); } } @@ -277,7 +289,9 @@ public class RNFirebaseNotifications extends ReactContextBaseJavaModule implemen notificationMap.putString("body", body); } if (message.getData() != null) { - for (Map.Entry e : message.getData().entrySet()) { + for (Map.Entry e : message + .getData() + .entrySet()) { dataMap.putString(e.getKey(), e.getValue()); } } @@ -315,27 +329,33 @@ public class RNFirebaseNotifications extends ReactContextBaseJavaModule implemen return notificationMap; } - private @Nullable String getNotificationBody(RemoteMessage.Notification notification) { + private @Nullable + String getNotificationBody(RemoteMessage.Notification notification) { String body = notification.getBody(); String bodyLocKey = notification.getBodyLocalizationKey(); if (bodyLocKey != null) { String[] bodyLocArgs = notification.getBodyLocalizationArgs(); Context ctx = getReactApplicationContext(); int resId = getResId(ctx, bodyLocKey); - return ctx.getResources().getString(resId, (Object[]) bodyLocArgs); + return ctx + .getResources() + .getString(resId, (Object[]) bodyLocArgs); } else { return body; } } - private @Nullable String getNotificationTitle(RemoteMessage.Notification notification) { + private @Nullable + String getNotificationTitle(RemoteMessage.Notification notification) { String title = notification.getTitle(); String titleLocKey = notification.getTitleLocalizationKey(); if (titleLocKey != null) { String[] titleLocArgs = notification.getTitleLocalizationArgs(); Context ctx = getReactApplicationContext(); int resId = getResId(ctx, titleLocKey); - return ctx.getResources().getString(resId, (Object[]) titleLocArgs); + return ctx + .getResources() + .getString(resId, (Object[]) titleLocArgs); } else { return title; } @@ -350,7 +370,11 @@ public class RNFirebaseNotifications extends ReactContextBaseJavaModule implemen RemoteMessage message = intent.getParcelableExtra("notification"); WritableMap messageMap = parseRemoteMessage(message); - Utils.sendEvent(getReactApplicationContext(), "notifications_notification_received", messageMap); + Utils.sendEvent( + getReactApplicationContext(), + "notifications_notification_received", + messageMap + ); } } } @@ -364,7 +388,11 @@ public class RNFirebaseNotifications extends ReactContextBaseJavaModule implemen Bundle notification = intent.getBundleExtra("notification"); WritableMap messageMap = parseNotificationBundle(notification); - Utils.sendEvent(getReactApplicationContext(), "notifications_notification_received", messageMap); + Utils.sendEvent( + getReactApplicationContext(), + "notifications_notification_received", + messageMap + ); } } } diff --git a/android/src/main/java/io/invertase/firebase/perf/RNFirebasePerformance.java b/android/src/main/java/io/invertase/firebase/perf/RNFirebasePerformance.java index 81defc82..38069744 100644 --- a/android/src/main/java/io/invertase/firebase/perf/RNFirebasePerformance.java +++ b/android/src/main/java/io/invertase/firebase/perf/RNFirebasePerformance.java @@ -3,18 +3,24 @@ package io.invertase.firebase.perf; import android.util.Log; +import com.facebook.react.bridge.Arguments; +import com.facebook.react.bridge.Promise; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.bridge.WritableMap; import com.google.firebase.perf.FirebasePerformance; import com.google.firebase.perf.metrics.Trace; +import com.google.firebase.perf.metrics.HttpMetric; import java.util.HashMap; +import java.util.Map; public class RNFirebasePerformance extends ReactContextBaseJavaModule { private static final String TAG = "RNFirebasePerformance"; private HashMap traces = new HashMap<>(); + private HashMap httpMetrics = new HashMap<>(); public RNFirebasePerformance(ReactApplicationContext reactContext) { super(reactContext); @@ -30,19 +36,79 @@ public class RNFirebasePerformance extends ReactContextBaseJavaModule { } @ReactMethod - public void setPerformanceCollectionEnabled(Boolean enabled) { + public void setPerformanceCollectionEnabled(Boolean enabled, Promise promise) { FirebasePerformance.getInstance().setPerformanceCollectionEnabled(enabled); + promise.resolve(null); + } + + /** + * Trace + */ + + @ReactMethod + public void getTraceAttribute(String identifier, String attribute, Promise promise) { + promise.resolve(getOrCreateTrace(identifier).getAttribute(attribute)); } @ReactMethod - public void start(String identifier) { + public void getTraceAttributes(String identifier, Promise promise) { + Map attributes = getOrCreateTrace(identifier).getAttributes(); + WritableMap map = Arguments.createMap(); + + for (Map.Entry entry : attributes.entrySet()) { + map.putString(entry.getKey(), entry.getValue()); + } + + promise.resolve(map); + } + + @ReactMethod + public void getTraceLongMetric(String identifier, String metricName, Promise promise) { + Integer value = Long.valueOf(getOrCreateTrace(identifier).getLongMetric(metricName)).intValue(); + promise.resolve(value); + } + + @ReactMethod + public void incrementTraceMetric(String identifier, String metricName, Integer incrementBy, Promise promise) { + getOrCreateTrace(identifier).incrementMetric(metricName, incrementBy.longValue()); + promise.resolve(null); + } + + @ReactMethod + public void putTraceAttribute(String identifier, String attribute, String value, Promise promise) { + getOrCreateTrace(identifier).putAttribute(attribute, value); + // Docs say it returns a bool, actually void so we internally check attributes + Map attributes = getOrCreateTrace(identifier).getAttributes(); + if (attributes.containsKey(attribute)) { + promise.resolve(true); + } else { + promise.resolve(false); + } + } + + @ReactMethod + public void putTraceMetric(String identifier, String metricName, Integer value, Promise promise) { + getOrCreateTrace(identifier).putMetric(metricName, value.longValue()); + promise.resolve(null); + } + + @ReactMethod + public void removeTraceAttribute(String identifier, String attribute, Promise promise) { + getOrCreateTrace(identifier).removeAttribute(attribute); + promise.resolve(null); + } + + @ReactMethod + public void startTrace(String identifier, Promise promise) { getOrCreateTrace(identifier).start(); + promise.resolve(null); } @ReactMethod - public void stop(String identifier) { + public void stopTrace(String identifier, Promise promise) { getOrCreateTrace(identifier).stop(); traces.remove(identifier); + promise.resolve(null); } @ReactMethod @@ -50,6 +116,86 @@ public class RNFirebasePerformance extends ReactContextBaseJavaModule { getOrCreateTrace(identifier).incrementCounter(event); } + /** + * Http Metric + */ + + @ReactMethod + public void getHttpMetricAttribute(String url, String httpMethod, String attribute, Promise promise) { + promise.resolve(getOrCreateHttpMetric(url, httpMethod).getAttribute(attribute)); + } + + @ReactMethod + public void getHttpMetricAttributes(String url, String httpMethod, Promise promise) { + Map attributes = getOrCreateHttpMetric(url, httpMethod).getAttributes(); + WritableMap map = Arguments.createMap(); + + for (Map.Entry entry : attributes.entrySet()) { + map.putString(entry.getKey(), entry.getValue()); + } + + promise.resolve(map); + } + + @ReactMethod + public void putHttpMetricAttribute(String url, String httpMethod, String attribute, String value, Promise promise) { + getOrCreateHttpMetric(url, httpMethod).putAttribute(attribute, value); + // Docs say it returns a bool, actually void so we internally check attributes + Map attributes = getOrCreateHttpMetric(url, httpMethod).getAttributes(); + if (attributes.containsKey(attribute)) { + promise.resolve( true); + } else { + promise.resolve(false); + } + } + + @ReactMethod + public void removeHttpMetricAttribute(String url, String httpMethod, String attribute, Promise promise) { + getOrCreateHttpMetric(url, httpMethod).removeAttribute(attribute); + promise.resolve(null); + } + + @ReactMethod + public void setHttpMetricResponseCode(String url, String httpMethod, Integer code, Promise promise) { + getOrCreateHttpMetric(url, httpMethod).setHttpResponseCode(code); + promise.resolve(null); + } + + @ReactMethod + public void setHttpMetricRequestPayloadSize(String url, String httpMethod, Integer bytes, Promise promise) { + getOrCreateHttpMetric(url, httpMethod).setRequestPayloadSize(bytes.longValue()); + promise.resolve(null); + } + + @ReactMethod + public void setHttpMetricResponseContentType(String url, String httpMethod, String type, Promise promise) { + getOrCreateHttpMetric(url, httpMethod).setResponseContentType(type); + promise.resolve(null); + } + + @ReactMethod + public void setHttpMetricResponsePayloadSize(String url, String httpMethod, Integer bytes, Promise promise) { + getOrCreateHttpMetric(url, httpMethod).setResponsePayloadSize(bytes.longValue()); + promise.resolve(null); + } + + @ReactMethod + public void startHttpMetric(String url, String httpMethod, Promise promise) { + getOrCreateHttpMetric(url, httpMethod).start(); + promise.resolve(null); + } + + @ReactMethod + public void stopHttpMetric(String url, String httpMethod, Promise promise) { + getOrCreateHttpMetric(url, httpMethod).stop(); + httpMetrics.remove(url + httpMethod); + promise.resolve(null); + } + + /** + * Private + */ + private Trace getOrCreateTrace(String identifier) { if (traces.containsKey(identifier)) { return traces.get(identifier); @@ -58,4 +204,39 @@ public class RNFirebasePerformance extends ReactContextBaseJavaModule { traces.put(identifier, trace); return trace; } + + private HttpMetric getOrCreateHttpMetric(String url, String httpMethod) { + String identifier = url + httpMethod; + if (httpMetrics.containsKey(identifier)) { + return httpMetrics.get(identifier); + } + HttpMetric httpMetric = FirebasePerformance.getInstance().newHttpMetric(url, this.mapStringToMethod(httpMethod)); + httpMetrics.put(identifier, httpMetric); + return httpMetric; + } + + private String mapStringToMethod(String value) { + switch (value) { + case "CONNECT": + return FirebasePerformance.HttpMethod.CONNECT; + case "DELETE": + return FirebasePerformance.HttpMethod.DELETE; + case "GET": + return FirebasePerformance.HttpMethod.GET; + case "HEAD": + return FirebasePerformance.HttpMethod.HEAD; + case "OPTIONS": + return FirebasePerformance.HttpMethod.OPTIONS; + case "PATCH": + return FirebasePerformance.HttpMethod.PATCH; + case "POST": + return FirebasePerformance.HttpMethod.POST; + case "PUT": + return FirebasePerformance.HttpMethod.PUT; + case "TRACE": + return FirebasePerformance.HttpMethod.TRACE; + } + + return ""; + } } diff --git a/android/src/main/java/io/invertase/firebase/storage/RNFirebaseStorage.java b/android/src/main/java/io/invertase/firebase/storage/RNFirebaseStorage.java index fb318621..81dd3879 100644 --- a/android/src/main/java/io/invertase/firebase/storage/RNFirebaseStorage.java +++ b/android/src/main/java/io/invertase/firebase/storage/RNFirebaseStorage.java @@ -41,7 +41,6 @@ import com.google.firebase.storage.OnProgressListener; import io.invertase.firebase.Utils; - @SuppressWarnings("WeakerAccess") public class RNFirebaseStorage extends ReactContextBaseJavaModule { @@ -111,17 +110,20 @@ public class RNFirebaseStorage extends ReactContextBaseJavaModule { @ReactMethod public void delete(String appName, final String path, final Promise promise) { StorageReference reference = this.getReference(path, appName); - reference.delete().addOnSuccessListener(new OnSuccessListener() { - @Override - public void onSuccess(Void aVoid) { - promise.resolve(null); - } - }).addOnFailureListener(new OnFailureListener() { - @Override - public void onFailure(@NonNull Exception exception) { - promiseRejectStorageException(promise, exception); - } - }); + reference + .delete() + .addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(Void aVoid) { + promise.resolve(null); + } + }) + .addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@NonNull Exception exception) { + promiseRejectStorageException(promise, exception); + } + }); } /** @@ -162,17 +164,20 @@ public class RNFirebaseStorage extends ReactContextBaseJavaModule { @ReactMethod public void getMetadata(String appName, final String path, final Promise promise) { StorageReference reference = this.getReference(path, appName); - reference.getMetadata().addOnSuccessListener(new OnSuccessListener() { - @Override - public void onSuccess(StorageMetadata storageMetadata) { - promise.resolve(getMetadataAsMap(storageMetadata)); - } - }).addOnFailureListener(new OnFailureListener() { - @Override - public void onFailure(@NonNull Exception exception) { - promiseRejectStorageException(promise, exception); - } - }); + reference + .getMetadata() + .addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(StorageMetadata storageMetadata) { + promise.resolve(getMetadataAsMap(storageMetadata)); + } + }) + .addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@NonNull Exception exception) { + promiseRejectStorageException(promise, exception); + } + }); } /** @@ -184,22 +189,30 @@ public class RNFirebaseStorage extends ReactContextBaseJavaModule { * @url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#updateMetadata */ @ReactMethod - public void updateMetadata(String appName, final String path, final ReadableMap metadata, final Promise promise) { + public void updateMetadata( + String appName, + final String path, + final ReadableMap metadata, + final Promise promise + ) { StorageReference reference = this.getReference(path, appName); StorageMetadata md = buildMetadataFromMap(metadata, null); - reference.updateMetadata(md).addOnSuccessListener(new OnSuccessListener() { - @Override - public void onSuccess(StorageMetadata storageMetadata) { - WritableMap data = getMetadataAsMap(storageMetadata); - promise.resolve(data); - } - }).addOnFailureListener(new OnFailureListener() { - @Override - public void onFailure(@NonNull Exception exception) { - promiseRejectStorageException(promise, exception); - } - }); + reference + .updateMetadata(md) + .addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(StorageMetadata storageMetadata) { + WritableMap data = getMetadataAsMap(storageMetadata); + promise.resolve(data); + } + }) + .addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@NonNull Exception exception) { + promiseRejectStorageException(promise, exception); + } + }); } @@ -212,7 +225,12 @@ public class RNFirebaseStorage extends ReactContextBaseJavaModule { * @url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#downloadFile */ @ReactMethod - public void downloadFile(final String appName, final String path, final String localPath, final Promise promise) { + public void downloadFile( + final String appName, + final String path, + final String localPath, + final Promise promise + ) { if (!isExternalStorageWritable()) { promise.reject( "storage/invalid-device-file-path", @@ -225,59 +243,70 @@ public class RNFirebaseStorage extends ReactContextBaseJavaModule { Log.d(TAG, "downloadFile path: " + path); StorageReference reference = this.getReference(path, appName); - reference.getStream(new StreamDownloadTask.StreamProcessor() { - @Override - public void doInBackground(StreamDownloadTask.TaskSnapshot taskSnapshot, InputStream inputStream) throws IOException { - int indexOfLastSlash = localPath.lastIndexOf("/"); - String pathMinusFileName = indexOfLastSlash > 0 ? localPath.substring(0, indexOfLastSlash) + "/" : "/"; - String filename = indexOfLastSlash > 0 ? localPath.substring(indexOfLastSlash + 1) : localPath; - File fileWithJustPath = new File(pathMinusFileName); + reference + .getStream(new StreamDownloadTask.StreamProcessor() { + @Override + public void doInBackground( + StreamDownloadTask.TaskSnapshot taskSnapshot, + InputStream inputStream + ) throws IOException { + int indexOfLastSlash = localPath.lastIndexOf("/"); + String pathMinusFileName = indexOfLastSlash > 0 ? localPath.substring( + 0, + indexOfLastSlash + ) + "/" : "/"; + String filename = indexOfLastSlash > 0 ? localPath.substring(indexOfLastSlash + 1) : localPath; + File fileWithJustPath = new File(pathMinusFileName); - // directoriesCreated assignment for not consumed warning - Boolean directoriesCreated = fileWithJustPath.mkdirs(); - File fileWithFullPath = new File(pathMinusFileName, filename); - FileOutputStream output = new FileOutputStream(fileWithFullPath); - int bufferSize = 1024; - byte[] buffer = new byte[bufferSize]; + // directoriesCreated assignment for not consumed warning + Boolean directoriesCreated = fileWithJustPath.mkdirs(); + File fileWithFullPath = new File(pathMinusFileName, filename); + FileOutputStream output = new FileOutputStream(fileWithFullPath); + int bufferSize = 1024; + byte[] buffer = new byte[bufferSize]; - int len; - while ((len = inputStream.read(buffer)) != -1) { - output.write(buffer, 0, len); + int len; + while ((len = inputStream.read(buffer)) != -1) { + output.write(buffer, 0, len); + } + + output.close(); } - - output.close(); - } - }).addOnProgressListener(new OnProgressListener() { - @Override - public void onProgress(StreamDownloadTask.TaskSnapshot taskSnapshot) { - Log.d(TAG, "downloadFile progress " + taskSnapshot); - WritableMap event = getDownloadTaskAsMap(taskSnapshot); - sendJSEvent(appName, STORAGE_STATE_CHANGED, path, event); - } - }).addOnPausedListener(new OnPausedListener() { - @Override - public void onPaused(StreamDownloadTask.TaskSnapshot taskSnapshot) { - Log.d(TAG, "downloadFile paused " + taskSnapshot); - WritableMap event = getDownloadTaskAsMap(taskSnapshot); - sendJSEvent(appName, STORAGE_STATE_CHANGED, path, event); - } - }).addOnSuccessListener(new OnSuccessListener() { - @Override - public void onSuccess(StreamDownloadTask.TaskSnapshot taskSnapshot) { - Log.d(TAG, "downloadFile success" + taskSnapshot); - WritableMap resp = getDownloadTaskAsMap(taskSnapshot); - sendJSEvent(appName, STORAGE_DOWNLOAD_SUCCESS, path, resp); - resp = getDownloadTaskAsMap(taskSnapshot); - promise.resolve(resp); - } - }).addOnFailureListener(new OnFailureListener() { - @Override - public void onFailure(@NonNull Exception exception) { - Log.e(TAG, "downloadFile failure " + exception.getMessage()); - // TODO sendJS error event - promiseRejectStorageException(promise, exception); - } - }); + }) + .addOnProgressListener(new OnProgressListener() { + @Override + public void onProgress(StreamDownloadTask.TaskSnapshot taskSnapshot) { + Log.d(TAG, "downloadFile progress " + taskSnapshot); + WritableMap event = getDownloadTaskAsMap(taskSnapshot); + sendJSEvent(appName, STORAGE_STATE_CHANGED, path, event); + } + }) + .addOnPausedListener(new OnPausedListener() { + @Override + public void onPaused(StreamDownloadTask.TaskSnapshot taskSnapshot) { + Log.d(TAG, "downloadFile paused " + taskSnapshot); + WritableMap event = getDownloadTaskAsMap(taskSnapshot); + sendJSEvent(appName, STORAGE_STATE_CHANGED, path, event); + } + }) + .addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(StreamDownloadTask.TaskSnapshot taskSnapshot) { + Log.d(TAG, "downloadFile success" + taskSnapshot); + WritableMap resp = getDownloadTaskAsMap(taskSnapshot); + sendJSEvent(appName, STORAGE_DOWNLOAD_SUCCESS, path, resp); + resp = getDownloadTaskAsMap(taskSnapshot); + promise.resolve(resp); + } + }) + .addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@NonNull Exception exception) { + Log.e(TAG, "downloadFile failure " + exception.getMessage()); + // TODO sendJS error event + promiseRejectStorageException(promise, exception); + } + }); } /** @@ -332,7 +361,13 @@ public class RNFirebaseStorage extends ReactContextBaseJavaModule { * @url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#putFile */ @ReactMethod - public void putFile(final String appName, final String path, final String localPath, final ReadableMap metadata, final Promise promise) { + public void putFile( + final String appName, + final String path, + final String localPath, + final ReadableMap metadata, + final Promise promise + ) { StorageReference reference = this.getReference(path, appName); Log.i(TAG, "putFile: " + localPath + " to " + path); @@ -436,7 +471,9 @@ public class RNFirebaseStorage extends ReactContextBaseJavaModule { private Uri getURI(final String uri) { Uri parsed = Uri.parse(uri); - if (parsed.getScheme() == null || parsed.getScheme().isEmpty()) { + if (parsed.getScheme() == null || parsed + .getScheme() + .isEmpty()) { return Uri.fromFile(new File(uri)); } return parsed; @@ -470,14 +507,18 @@ public class RNFirebaseStorage extends ReactContextBaseJavaModule { } else if (file != null) { String mimeType = null; - if (file.getScheme().equals(ContentResolver.SCHEME_CONTENT)) { + if (file + .getScheme() + .equals(ContentResolver.SCHEME_CONTENT)) { ContentResolver cr = getReactApplicationContext().getContentResolver(); mimeType = cr.getType(file); } else { String fileExtension = MimeTypeMap.getFileExtensionFromUrl(file - .toString()); - mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension( - fileExtension.toLowerCase()); + .toString()); + mimeType = MimeTypeMap + .getSingleton() + .getMimeTypeFromExtension( + fileExtension.toLowerCase()); } if (mimeType != null) metadataBuilder.setContentType(mimeType); @@ -498,7 +539,12 @@ public class RNFirebaseStorage extends ReactContextBaseJavaModule { private WritableMap getDownloadTaskAsMap(final StreamDownloadTask.TaskSnapshot taskSnapshot) { WritableMap resp = Arguments.createMap(); resp.putDouble("bytesTransferred", taskSnapshot.getBytesTransferred()); - resp.putString("ref", taskSnapshot.getStorage().getPath()); + resp.putString( + "ref", + taskSnapshot + .getStorage() + .getPath() + ); resp.putString("state", this.getTaskStatus(taskSnapshot.getTask())); resp.putDouble("totalBytes", taskSnapshot.getTotalByteCount()); @@ -512,29 +558,40 @@ public class RNFirebaseStorage extends ReactContextBaseJavaModule { * @param taskSnapshot * @return */ - private void getUploadTaskAsMap(final UploadTask.TaskSnapshot taskSnapshot, final OnSuccessListener listener) { + private void getUploadTaskAsMap( + final UploadTask.TaskSnapshot taskSnapshot, + final OnSuccessListener listener + ) { if (taskSnapshot != null) { - taskSnapshot.getStorage().getDownloadUrl().addOnSuccessListener(new OnSuccessListener() { - @Override - public void onSuccess(Uri downloadUrl) { - WritableMap resp = Arguments.createMap(); + taskSnapshot + .getStorage() + .getDownloadUrl() + .addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(Uri downloadUrl) { + WritableMap resp = Arguments.createMap(); - resp.putDouble("bytesTransferred", taskSnapshot.getBytesTransferred()); - resp.putString("downloadURL", downloadUrl.toString()); + resp.putDouble("bytesTransferred", taskSnapshot.getBytesTransferred()); + resp.putString("downloadURL", downloadUrl.toString()); - StorageMetadata d = taskSnapshot.getMetadata(); - if (d != null) { - WritableMap metadata = getMetadataAsMap(d); - resp.putMap("metadata", metadata); + StorageMetadata d = taskSnapshot.getMetadata(); + if (d != null) { + WritableMap metadata = getMetadataAsMap(d); + resp.putMap("metadata", metadata); + } + + resp.putString( + "ref", + taskSnapshot + .getStorage() + .getPath() + ); + resp.putString("state", RNFirebaseStorage.this.getTaskStatus(taskSnapshot.getTask())); + resp.putDouble("totalBytes", taskSnapshot.getTotalByteCount()); + + listener.onSuccess(resp); } - - resp.putString("ref", taskSnapshot.getStorage().getPath()); - resp.putString("state", RNFirebaseStorage.this.getTaskStatus(taskSnapshot.getTask())); - resp.putDouble("totalBytes", taskSnapshot.getTotalByteCount()); - - listener.onSuccess(resp); - } - }); + }); } else { listener.onSuccess(Arguments.createMap()); } @@ -683,10 +740,33 @@ public class RNFirebaseStorage extends ReactContextBaseJavaModule { public Map getConstants() { final Map constants = new HashMap<>(); - constants.put(DocumentDirectoryPath, this.getReactApplicationContext().getFilesDir().getAbsolutePath()); - constants.put(TemporaryDirectoryPath, this.getReactApplicationContext().getCacheDir().getAbsolutePath()); - constants.put(PicturesDirectoryPath, Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getAbsolutePath()); - constants.put(CachesDirectoryPath, this.getReactApplicationContext().getCacheDir().getAbsolutePath()); + constants.put( + DocumentDirectoryPath, + this + .getReactApplicationContext() + .getFilesDir() + .getAbsolutePath() + ); + constants.put( + TemporaryDirectoryPath, + this + .getReactApplicationContext() + .getCacheDir() + .getAbsolutePath() + ); + constants.put( + PicturesDirectoryPath, + Environment + .getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + .getAbsolutePath() + ); + constants.put( + CachesDirectoryPath, + this + .getReactApplicationContext() + .getCacheDir() + .getAbsolutePath() + ); constants.put(FileTypeRegular, 0); constants.put(FileTypeDirectory, 1); @@ -697,7 +777,9 @@ public class RNFirebaseStorage extends ReactContextBaseJavaModule { constants.put(ExternalStorageDirectoryPath, null); } - File externalDirectory = this.getReactApplicationContext().getExternalFilesDir(null); + File externalDirectory = this + .getReactApplicationContext() + .getExternalFilesDir(null); if (externalDirectory != null) { constants.put(ExternalDirectoryPath, externalDirectory.getAbsolutePath()); } else { diff --git a/bridge/android/build.gradle b/bridge/android/build.gradle index 1fdb7242..f1936428 100755 --- a/bridge/android/build.gradle +++ b/bridge/android/build.gradle @@ -9,7 +9,7 @@ buildscript { dependencies { classpath 'com.android.tools.build:gradle:3.1.3' classpath 'com.google.gms:google-services:4.0.1' - classpath 'com.google.firebase:firebase-plugins:1.1.1' + classpath 'com.google.firebase:firebase-plugins:1.1.5' classpath 'io.fabric.tools:gradle:1.25.4' } } diff --git a/bridge/e2e/perf/httpMetric.e2e.js b/bridge/e2e/perf/httpMetric.e2e.js new file mode 100644 index 00000000..a4968e32 --- /dev/null +++ b/bridge/e2e/perf/httpMetric.e2e.js @@ -0,0 +1,93 @@ +describe('perf()', () => { + describe('HttpMetric', () => { + it('start() & stop()', async () => { + const httpMetric = firebase.perf().newHttpMetric('http://foo.com', 'GET'); + await httpMetric.start(); + await httpMetric.stop(); + }); + + it('removeAttribute()', async () => { + const httpMetric = firebase.perf().newHttpMetric('http://foo.com', 'GET'); + await httpMetric.start(); + await httpMetric.putAttribute('foo', 'bar'); + const value = await httpMetric.getAttribute('foo'); + should.equal(value, 'bar'); + await httpMetric.removeAttribute('foo'); + const value2 = await httpMetric.getAttribute('foo'); + should.equal(value2, null); + await httpMetric.stop(); + }); + + it('getAttribute() should return null', async () => { + const httpMetric = firebase.perf().newHttpMetric('http://foo.com', 'GET'); + await httpMetric.start(); + const value = await httpMetric.getAttribute('foo'); + should.equal(value, null); + await httpMetric.removeAttribute('foo'); + await httpMetric.stop(); + }); + + it('getAttribute() should return string value', async () => { + const httpMetric = firebase.perf().newHttpMetric('http://foo.com', 'GET'); + await httpMetric.start(); + await httpMetric.putAttribute('foo', 'bar'); + const value = await httpMetric.getAttribute('foo'); + should.equal(value, 'bar'); + await httpMetric.removeAttribute('foo'); + await httpMetric.stop(); + }); + + it('putAttribute()', async () => { + const httpMetric = firebase.perf().newHttpMetric('http://foo.com', 'GET'); + await httpMetric.start(); + await httpMetric.putAttribute('foo', 'bar'); + const value = await httpMetric.getAttribute('foo'); + value.should.equal('bar'); + await httpMetric.removeAttribute('foo'); + await httpMetric.stop(); + }); + + it('getAttributes()', async () => { + const httpMetric = firebase.perf().newHttpMetric('http://foo.com', 'GET'); + await httpMetric.start(); + await httpMetric.putAttribute('foo', 'bar'); + await httpMetric.putAttribute('bar', 'baz'); + const value = await httpMetric.getAttributes(); + value.should.deepEqual({ + foo: 'bar', + bar: 'baz', + }); + await httpMetric.removeAttribute('foo'); + await httpMetric.removeAttribute('bar'); + await httpMetric.stop(); + }); + + it('setHttpResponseCode()', async () => { + const httpMetric = firebase.perf().newHttpMetric('http://foo.com', 'GET'); + await httpMetric.start(); + await httpMetric.setHttpResponseCode(500); + await httpMetric.stop(); + }); + + it('setRequestPayloadSize()', async () => { + const httpMetric = firebase.perf().newHttpMetric('http://foo.com', 'GET'); + await httpMetric.start(); + await httpMetric.setRequestPayloadSize(1234567); + await httpMetric.stop(); + }); + + it('setResponseContentType()', async () => { + const httpMetric = firebase.perf().newHttpMetric('http://foo.com', 'GET'); + await httpMetric.start(); + await httpMetric.setResponseContentType('application/foobar'); + await httpMetric.stop(); + }); + + it('setResponsePayloadSize()', async () => { + const httpMetric = firebase.perf().newHttpMetric('http://foo.com', 'GET'); + await httpMetric.start(); + await httpMetric.setResponsePayloadSize(123456789); + await httpMetric.stop(); + }); + }); +}); diff --git a/bridge/e2e/perf/perf.e2e.js b/bridge/e2e/perf/perf.e2e.js index 6d614f1d..78df76c4 100644 --- a/bridge/e2e/perf/perf.e2e.js +++ b/bridge/e2e/perf/perf.e2e.js @@ -8,9 +8,10 @@ describe('perf()', () => { await firebase.perf().setPerformanceCollectionEnabled(false); }); - xit('errors if not boolean', async () => { - // TODO add validations to lib - await firebase.perf().setPerformanceCollectionEnabled(); + it('errors if not boolean', async () => { + (() => firebase.perf().setPerformanceCollectionEnabled()).should.throw( + 'firebase.perf().setPerformanceCollectionEnabled() requires a boolean value' + ); }); }); @@ -20,15 +21,27 @@ describe('perf()', () => { trace.constructor.name.should.be.equal('Trace'); }); - xit('errors if identifier not a string', async () => { - // TODO add validations to lib - try { - firebase.perf().newTrace([1, 2, 3, 4]); - } catch (e) { - return undefined; - } + it('errors if identifier not a string', async () => { + (() => firebase.perf().newTrace([1, 2, 3, 4])).should.throw( + 'firebase.perf().newTrace() requires a string value' + ); + }); + }); - throw new Error('Trace did not error on invalid identifier'); + describe('newHttpMetric()', () => { + it('returns an instance of HttpMetric', async () => { + const trace = firebase.perf().newHttpMetric('http://foo.com', 'GET'); + trace.constructor.name.should.be.equal('HttpMetric'); + }); + + it('errors if url/httpMethod not a string', async () => { + (() => firebase.perf().newHttpMetric(123, [1, 2])).should.throw( + 'firebase.perf().newHttpMetric() requires url and httpMethod string values' + ); + }); + + it('errors if httpMethod not a valid type', async () => { + (() => firebase.perf().newHttpMetric('foo', 'FOO')).should.throw(); // TODO error }); }); }); diff --git a/bridge/e2e/perf/trace.e2e.js b/bridge/e2e/perf/trace.e2e.js index 0751dcf7..d9d118e5 100644 --- a/bridge/e2e/perf/trace.e2e.js +++ b/bridge/e2e/perf/trace.e2e.js @@ -6,23 +6,83 @@ describe('perf()', () => { await trace.stop(); }); - describe('incrementCounter()', () => { - it('accepts a string event', async () => { - const trace = firebase.perf().newTrace('bar'); - await trace.start(); - await trace.incrementCounter('fooby'); - await trace.incrementCounter('fooby'); - await trace.incrementCounter('fooby'); - await trace.incrementCounter('fooby'); - await trace.stop(); - }); - - xit('errors if event is not a string', async () => { - const trace = firebase.perf().newTrace('bar'); - await trace.start(); - await trace.incrementCounter([1, 2, 3, 4]); - await trace.stop(); - }); + it('getAttribute() should return null', async () => { + const trace = firebase.perf().newTrace('bar'); + await trace.start(); + const value = await trace.getAttribute('foo'); + should.equal(value, null); + await trace.stop(); }); + + it('getAttribute() should return string value', async () => { + const trace = firebase.perf().newTrace('bar'); + await trace.start(); + await trace.putAttribute('foo', 'bar'); + const value = await trace.getAttribute('foo'); + should.equal(value, 'bar'); + await trace.stop(); + }); + + it('putAttribute()', async () => { + const trace = firebase.perf().newTrace('bar'); + await trace.start(); + await trace.putAttribute('foo', 'bar'); + const value = await trace.getAttribute('foo'); + value.should.equal('bar'); + await trace.stop(); + }); + + it('getAttributes()', async () => { + const trace = firebase.perf().newTrace('bar'); + await trace.start(); + await trace.putAttribute('foo', 'bar'); + await trace.putAttribute('bar', 'baz'); + const value = await trace.getAttributes(); + value.should.deepEqual({ + foo: 'bar', + bar: 'baz', + }); + await trace.stop(); + }); + + it('removeAttribute()', async () => { + const trace = firebase.perf().newTrace('bar'); + await trace.start(); + await trace.putAttribute('foobar', 'bar'); + const value = await trace.getAttribute('foobar'); + value.should.equal('bar'); + await trace.removeAttribute('foobar'); + const removed = await trace.getAttribute('foobar'); + should.equal(removed, null); + await trace.stop(); + }); + + it('getMetric()', async () => { + const trace = firebase.perf().newTrace('bar'); + await trace.start(); + const metric = await trace.getMetric('foo'); + metric.should.equal(0); + await trace.stop(); + }); + + it('putMetric()', async () => { + const trace = firebase.perf().newTrace('bar'); + await trace.start(); + await trace.putMetric('baz', 1); + const metric = await trace.getMetric('baz'); + metric.should.equal(1); + await trace.stop(); + }); + + it('incrementMetric()', async () => { + const trace = firebase.perf().newTrace('bar'); + await trace.start(); + await trace.putMetric('baz', 1); + await trace.incrementMetric('baz', 2); + const metric = await trace.getMetric('baz'); + metric.should.equal(3); + await trace.stop(); + }); + }); }); diff --git a/ios/RNFirebase/perf/RNFirebasePerformance.h b/ios/RNFirebase/perf/RNFirebasePerformance.h index ea65d539..4871b158 100644 --- a/ios/RNFirebase/perf/RNFirebasePerformance.h +++ b/ios/RNFirebase/perf/RNFirebasePerformance.h @@ -10,6 +10,7 @@ } @property NSMutableDictionary *traces; +@property NSMutableDictionary *httpMetrics; @end diff --git a/ios/RNFirebase/perf/RNFirebasePerformance.m b/ios/RNFirebase/perf/RNFirebasePerformance.m index de8e7b9b..f3d4c26f 100644 --- a/ios/RNFirebase/perf/RNFirebasePerformance.m +++ b/ios/RNFirebase/perf/RNFirebasePerformance.m @@ -2,6 +2,7 @@ #if __has_include() #import +#import @implementation RNFirebasePerformance RCT_EXPORT_MODULE(); @@ -9,10 +10,25 @@ RCT_EXPORT_MODULE(); self = [super init]; if (self != nil) { _traces = [[NSMutableDictionary alloc] init]; + _httpMetrics = [[NSMutableDictionary alloc] init]; } return self; } +- (FIRHTTPMethod) mapStringToMethod:(NSString *) value { + if ([value compare:@"get" options:NSCaseInsensitiveSearch] == NSOrderedSame) return FIRHTTPMethodGET; + if ([value compare:@"put" options:NSCaseInsensitiveSearch] == NSOrderedSame) return FIRHTTPMethodPUT; + if ([value compare:@"post" options:NSCaseInsensitiveSearch] == NSOrderedSame) return FIRHTTPMethodPUT; + if ([value compare:@"delete" options:NSCaseInsensitiveSearch] == NSOrderedSame) return FIRHTTPMethodDELETE; + if ([value compare:@"head" options:NSCaseInsensitiveSearch] == NSOrderedSame) return FIRHTTPMethodHEAD; + if ([value compare:@"patch" options:NSCaseInsensitiveSearch] == NSOrderedSame) return FIRHTTPMethodPATCH; + if ([value compare:@"options" options:NSCaseInsensitiveSearch] == NSOrderedSame) return FIRHTTPMethodOPTIONS; + if ([value compare:@"trace" options:NSCaseInsensitiveSearch] == NSOrderedSame) return FIRHTTPMethodTRACE; + if ([value compare:@"connect" options:NSCaseInsensitiveSearch] == NSOrderedSame) return FIRHTTPMethodCONNECT; + return FIRHTTPMethodGET; +} + + - (FIRTrace *)getOrCreateTrace:(NSString *)identifier { if (_traces[identifier]) { return _traces[identifier]; @@ -22,27 +38,223 @@ RCT_EXPORT_MODULE(); return trace; } +- (FIRHTTPMetric *)getOrCreateHttpMetric:(NSString *)url httpMethod:(NSString *) httpMethod { + NSString *identifier = [NSString stringWithFormat:@"%@%@", url, httpMethod]; + if (_httpMetrics[identifier]) { + return _httpMetrics[identifier]; + } + NSURL * toURL = [NSURL URLWithString:url]; + FIRHTTPMethod method = [self mapStringToMethod:httpMethod]; + FIRHTTPMetric *httpMetric = [[FIRHTTPMetric alloc] initWithURL:toURL HTTPMethod:method]; + _httpMetrics[identifier] = httpMetric; + return httpMetric; +} + RCT_EXPORT_METHOD(setPerformanceCollectionEnabled: (BOOL *) enabled) { [FIRPerformance sharedInstance].dataCollectionEnabled = (BOOL) enabled; } -RCT_EXPORT_METHOD(start: - (NSString *) identifier) { +/** + * Trace + */ + +RCT_EXPORT_METHOD(startTrace: + (NSString *) identifier + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) { [[self getOrCreateTrace:identifier] start]; + resolve([NSNull null]); } -RCT_EXPORT_METHOD(stop: - (NSString *) identifier) { +RCT_EXPORT_METHOD(stopTrace: + (NSString *) identifier + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) { [[self getOrCreateTrace:identifier] stop]; - _traces[identifier] = nil; + [_traces removeObjectForKey:identifier]; + + resolve([NSNull null]); } -RCT_EXPORT_METHOD(incrementCounter: - (NSString *) identifier - event: - (NSString *) event) { - [[self getOrCreateTrace:identifier] incrementCounterNamed:event]; +RCT_EXPORT_METHOD(getTraceAttribute: + (NSString *) identifier + attribute:(NSString *) attribute + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) { + NSString *value = [[self getOrCreateTrace:identifier] valueForAttribute:attribute]; + resolve(value ? value : [NSNull null]); +} + +RCT_EXPORT_METHOD(getTraceAttributes: + (NSString *) identifier + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) { + resolve([[self getOrCreateTrace:identifier] attributes]); +} + +RCT_EXPORT_METHOD(getTraceLongMetric: + (NSString *) identifier + metricName:(NSString *) metricName + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) { + int64_t value = [[self getOrCreateTrace:identifier] valueForIntMetric:metricName]; + resolve(@(value)); +} + +RCT_EXPORT_METHOD(incrementTraceMetric: + (NSString *) identifier + metricName:(NSString *) metricName + incrementBy:(NSNumber *) incrementBy + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) { + int64_t byInt = [incrementBy intValue]; + [[self getOrCreateTrace:identifier] incrementMetric:metricName byInt:byInt]; + resolve([NSNull null]); +} + +RCT_EXPORT_METHOD(putTraceAttribute: + (NSString *) identifier + attribute:(NSString *) attribute + value:(NSString *) value + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) { + FIRTrace * trace = [self getOrCreateTrace:identifier]; + [trace setValue:value forAttribute:attribute]; + + if (trace.attributes[attribute] != nil) { + resolve(@(YES)); + } else { + resolve(@(NO)); + } +} + +RCT_EXPORT_METHOD(putTraceMetric: + (NSString *) identifier + attribute:(NSString *) attribute + value:(NSNumber *) value + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) { + int64_t byInt = [value intValue]; + [[self getOrCreateTrace:identifier] setIntValue:byInt forMetric:attribute]; + resolve([NSNull null]); +} + +RCT_EXPORT_METHOD(removeTraceAttribute: + (NSString *) identifier + attribute:(NSString *) attribute + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) { + [[self getOrCreateTrace:identifier] removeAttribute:attribute]; + resolve([NSNull null]); +} + +/** + * HTTP Metric + */ + +RCT_EXPORT_METHOD(startHttpMetric: + (NSString *) url + httpMethod:(NSString *) httpMethod + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) { + [[self getOrCreateHttpMetric:url httpMethod:httpMethod] start]; + resolve([NSNull null]); +} + +RCT_EXPORT_METHOD(stopHttpMetric: + (NSString *) url + httpMethod:(NSString *) httpMethod + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) { + [[self getOrCreateHttpMetric:url httpMethod:httpMethod] stop]; + [_httpMetrics removeObjectForKey:[NSString stringWithFormat:@"%@%@", url, httpMethod]]; + resolve([NSNull null]); +} + +RCT_EXPORT_METHOD(getHttpMetricAttribute: + (NSString *) url + httpMethod:(NSString *) httpMethod + attribute:(NSString *) attribute + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) { + NSString *value = [[self getOrCreateHttpMetric:url httpMethod:httpMethod] valueForAttribute:attribute]; + resolve(value ? value : [NSNull null]); +} + +RCT_EXPORT_METHOD(getHttpMetricAttributes: + (NSString *) url + httpMethod:(NSString *) httpMethod + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) { + resolve([[self getOrCreateHttpMetric:url httpMethod:httpMethod] attributes]); +} + +RCT_EXPORT_METHOD(putHttpMetricAttribute: + (NSString *) url + httpMethod:(NSString *) httpMethod + attribute:(NSString *) attribute + value:(NSString *) value + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) { + FIRHTTPMetric * httpMetric = [self getOrCreateHttpMetric:url httpMethod:httpMethod]; + [httpMetric setValue:value forAttribute:attribute]; + + if (httpMetric.attributes[attribute] != nil) { + resolve(@(YES)); + } else { + resolve(@(NO)); + } +} + +RCT_EXPORT_METHOD(removeHttpMetricAttribute: + (NSString *) url + httpMethod:(NSString *) httpMethod + attribute:(NSString *) attribute + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) { + [[self getOrCreateHttpMetric:url httpMethod:httpMethod] removeAttribute:attribute]; + resolve([NSNull null]); +} + +RCT_EXPORT_METHOD(setHttpMetricResponseCode: + (NSString *) url + httpMethod:(NSString *) httpMethod + code:(NSNumber *) code + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) { + [[self getOrCreateHttpMetric:url httpMethod:httpMethod] setResponseCode:[code integerValue]]; + resolve([NSNull null]); +} + +RCT_EXPORT_METHOD(setHttpMetricRequestPayloadSize: + (NSString *) url + httpMethod:(NSString *) httpMethod + bytes:(NSNumber *) bytes + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) { + [[self getOrCreateHttpMetric:url httpMethod:httpMethod] setRequestPayloadSize:[bytes longLongValue]]; + resolve([NSNull null]); +} + +RCT_EXPORT_METHOD(setHttpMetricResponseContentType: + (NSString *) url + httpMethod:(NSString *) httpMethod + type:(NSString *) type + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) { + [[self getOrCreateHttpMetric:url httpMethod:httpMethod] setResponseContentType:type]; + resolve([NSNull null]); +} + +RCT_EXPORT_METHOD(setHttpMetricResponsePayloadSize: + (NSString *) url + httpMethod:(NSString *) httpMethod + bytes:(NSNumber *) bytes + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) { + [[self getOrCreateHttpMetric:url httpMethod:httpMethod] setResponsePayloadSize:[bytes longLongValue]]; + resolve([NSNull null]); } + (BOOL)requiresMainQueueSetup diff --git a/lib/index.d.ts b/lib/index.d.ts index 33ca790e..8efe1ccc 100644 --- a/lib/index.d.ts +++ b/lib/index.d.ts @@ -53,7 +53,7 @@ declare module 'react-native-firebase' { RNFirebase.notifications.Notifications, RNFirebase.notifications.NotificationsStatics >; - // perf: FirebaseModuleAndStatics; + perf: FirebaseModuleAndStatics; storage: FirebaseModuleAndStatics; // utils: FirebaseModuleAndStatics; initializeApp(options: Firebase.Options, name: string): App; @@ -90,7 +90,7 @@ declare module 'react-native-firebase' { links(): RNFirebase.links.Links; messaging(): RNFirebase.messaging.Messaging; notifications(): RNFirebase.notifications.Notifications; - // perf(): RNFirebase.perf.Performance; + perf(): RNFirebase.perf.Perf; storage(): RNFirebase.storage.Storage; // utils(): RNFirebase.utils.Utils; readonly name: string; @@ -1546,6 +1546,135 @@ declare module 'react-native-firebase' { } } + namespace perf { + type HttpMethod = + | 'CONNECT' + | 'DELETE' + | 'GET' + | 'HEAD' + | 'OPTIONS' + | 'PATCH' + | 'POST' + | 'PUT' + | 'TRACE'; + + interface Perf { + /** + * Globally enable or disable performance monitoring. + */ + setPerformanceCollectionEnabled(enabled: boolean): void; + + /** + * Returns a new Trace instance. + */ + newTrace(trace: string): Trace; + + /** + * Returns a new HTTP Metric instance. + */ + newHttpMetric(url: string, httpMethod: HttpMethod): HttpMetric; + } + + interface Trace { + /** + * Return an attribute by name, or null if it does not exist. + */ + getAttribute(attribute: string): Promise; + + /** + * Return an object of key-value attributes. + */ + getAttributes(): Promise; + + /** + * Get a metric by name. Returns 0 if it does not exist. + */ + getMetric(metricName: string): Promise; + + /** + * Increment a metric by name and value. + */ + incrementMetric(metricName: string, incrementBy: number): Promise; + + /** + * Set an attribute. Returns true if it was set, false if it was not. + */ + putAttribute(attribute: string, value: string): Promise; + + /** + * Set a metric. + */ + putMetric(metricName: string, value: number): Promise; + + /** + * Remove an attribute by name. + */ + removeAttribute(attribute: string): Promise; + + /** + * Start a Trace instance. + */ + start(): Promise; + + /** + * Stop a Trace instance. + */ + stop(): Promise; + } + + interface HttpMetric { + /** + * Return an attribute by name, or null if it does not exist. + */ + getAttribute(attribute: string): Promise; + + /** + * Return an object of key-value attributes. + */ + getAttributes(): Promise + + /** + * Set an attribute. Returns true if it was set, false if it was not. + */ + putAttribute(attribute: string, value: string): Promise; + + /** + * Remove an attribute by name. + */ + removeAttribute(attribute: string): Promise; + + /** + * Set the request HTTP response code. + */ + setHttpResponseCode(code: number): Promise; + + /** + * Set the request payload size, in bytes. + */ + setRequestPayloadSize(bytes: number): Promise; + + /** + * Set the response content type. + */ + setResponseContentType(type: string): Promise; + + /** + * Set the response payload size, in bytes. + */ + setResponsePayloadSize(bytes: number): Promise; + + /** + * Start a HttpMetric instance. + */ + start(): Promise; + + /** + * Stop a HttpMetric instance. + */ + stop(): Promise; + } + } + namespace crashlytics { interface Crashlytics { /** diff --git a/lib/modules/perf/HttpMetric.js b/lib/modules/perf/HttpMetric.js new file mode 100644 index 00000000..bccd8df2 --- /dev/null +++ b/lib/modules/perf/HttpMetric.js @@ -0,0 +1,96 @@ +/** + * @flow + * Trace representation wrapper + */ +import { getNativeModule } from '../../utils/native'; +import type PerformanceMonitoring from './'; + +export default class HttpMetric { + url: string; + httpMethod: string; + _perf: PerformanceMonitoring; + + constructor(perf: PerformanceMonitoring, url: string, httpMethod: string) { + this._perf = perf; + this.url = url; + this.httpMethod = httpMethod; + } + + getAttribute(attribute: string): Promise { + return getNativeModule(this._perf).getHttpMetricAttribute( + this.url, + this.httpMethod, + attribute + ); + } + + getAttributes(): Promise { + return getNativeModule(this._perf).getHttpMetricAttributes( + this.url, + this.httpMethod + ); + } + + putAttribute(attribute: string, value: string): Promise { + return getNativeModule(this._perf).putHttpMetricAttribute( + this.url, + this.httpMethod, + attribute, + value + ); + } + + removeAttribute(attribute: string): Promise { + return getNativeModule(this._perf).removeHttpMetricAttribute( + this.url, + this.httpMethod, + attribute + ); + } + + setHttpResponseCode(code: number): Promise { + return getNativeModule(this._perf).setHttpMetricResponseCode( + this.url, + this.httpMethod, + code + ); + } + + setRequestPayloadSize(bytes: number): Promise { + return getNativeModule(this._perf).setHttpMetricRequestPayloadSize( + this.url, + this.httpMethod, + bytes + ); + } + + setResponseContentType(type: string): Promise { + return getNativeModule(this._perf).setHttpMetricResponseContentType( + this.url, + this.httpMethod, + type + ); + } + + setResponsePayloadSize(bytes: number): Promise { + return getNativeModule(this._perf).setHttpMetricResponsePayloadSize( + this.url, + this.httpMethod, + bytes + ); + } + + start(): Promise { + return getNativeModule(this._perf).startHttpMetric( + this.url, + this.httpMethod + ); + } + + stop(): Promise { + return getNativeModule(this._perf).stopHttpMetric( + this.url, + this.httpMethod + ); + } +} diff --git a/lib/modules/perf/Trace.js b/lib/modules/perf/Trace.js index 5fd54608..a2babf77 100644 --- a/lib/modules/perf/Trace.js +++ b/lib/modules/perf/Trace.js @@ -14,15 +14,60 @@ export default class Trace { this.identifier = identifier; } - start(): void { - getNativeModule(this._perf).start(this.identifier); + getAttribute(attribute: string): Promise { + return getNativeModule(this._perf).getTraceAttribute( + this.identifier, + attribute + ); } - stop(): void { - getNativeModule(this._perf).stop(this.identifier); + getAttributes(): Promise { + return getNativeModule(this._perf).getTraceAttributes(this.identifier); } - incrementCounter(event: string): void { - getNativeModule(this._perf).incrementCounter(this.identifier, event); + getMetric(metricName: string): Promise { + return getNativeModule(this._perf).getTraceLongMetric( + this.identifier, + metricName + ); + } + + incrementMetric(metricName: string, incrementBy: number): Promise { + return getNativeModule(this._perf).incrementTraceMetric( + this.identifier, + metricName, + incrementBy + ); + } + + putAttribute(attribute: string, value: string): Promise { + return getNativeModule(this._perf).putTraceAttribute( + this.identifier, + attribute, + value + ); + } + + putMetric(metricName: string, value: number): Promise { + return getNativeModule(this._perf).putTraceMetric( + this.identifier, + metricName, + value + ); + } + + removeAttribute(attribute: string): Promise { + return getNativeModule(this._perf).removeTraceAttribute( + this.identifier, + attribute + ); + } + + start(): Promise { + return getNativeModule(this._perf).startTrace(this.identifier); + } + + stop(): Promise { + return getNativeModule(this._perf).stopTrace(this.identifier); } } diff --git a/lib/modules/perf/index.js b/lib/modules/perf/index.js index c22ed35e..a7a25ad7 100644 --- a/lib/modules/perf/index.js +++ b/lib/modules/perf/index.js @@ -3,6 +3,7 @@ * Performance monitoring representation wrapper */ import Trace from './Trace'; +import HttpMetric from './HttpMetric'; import ModuleBase from '../../utils/ModuleBase'; import { getNativeModule } from '../../utils/native'; @@ -11,6 +12,29 @@ import type App from '../core/app'; export const MODULE_NAME = 'RNFirebasePerformance'; export const NAMESPACE = 'perf'; +const HTTP_METHODS = { + CONNECT: true, + DELETE: true, + GET: true, + HEAD: true, + OPTIONS: true, + PATCH: true, + POST: true, + PUT: true, + TRACE: true, +}; + +type HttpMethod = + | 'CONNECT' + | 'DELETE' + | 'GET' + | 'HEAD' + | 'OPTIONS' + | 'PATCH' + | 'POST' + | 'PUT' + | 'TRACE'; + export default class PerformanceMonitoring extends ModuleBase { constructor(app: App) { super(app, { @@ -27,7 +51,13 @@ export default class PerformanceMonitoring extends ModuleBase { * @returns {*} */ setPerformanceCollectionEnabled(enabled: boolean): void { - getNativeModule(this).setPerformanceCollectionEnabled(enabled); + if (typeof enabled !== 'boolean') { + throw new Error( + 'firebase.perf().setPerformanceCollectionEnabled() requires a boolean value' + ); + } + + return getNativeModule(this).setPerformanceCollectionEnabled(enabled); } /** @@ -35,8 +65,36 @@ export default class PerformanceMonitoring extends ModuleBase { * @param trace */ newTrace(trace: string): Trace { + if (typeof trace !== 'string') { + throw new Error('firebase.perf().newTrace() requires a string value'); + } + return new Trace(this, trace); } + + /** + * Return a new HttpMetric instance + * @param url + * @param httpMethod + * @returns {HttpMetric} + */ + newHttpMetric(url: string, httpMethod: HttpMethod): HttpMetric { + if (typeof url !== 'string' || typeof httpMethod !== 'string') { + throw new Error( + 'firebase.perf().newHttpMetric() requires url and httpMethod string values' + ); + } + + if (!HTTP_METHODS[httpMethod]) { + throw new Error( + `firebase.perf().newHttpMetric() httpMethod should be one of ${Object.keys( + HTTP_METHODS + ).join(', ')}` + ); + } + + return new HttpMetric(this, url, httpMethod); + } } export const statics = {};