diff options
Diffstat (limited to 'StoneIsland/plugins/cordova-plugin-firebasex/src/android/FirebasePlugin.java')
| -rw-r--r-- | StoneIsland/plugins/cordova-plugin-firebasex/src/android/FirebasePlugin.java | 2441 |
1 files changed, 2441 insertions, 0 deletions
diff --git a/StoneIsland/plugins/cordova-plugin-firebasex/src/android/FirebasePlugin.java b/StoneIsland/plugins/cordova-plugin-firebasex/src/android/FirebasePlugin.java new file mode 100644 index 00000000..d81419e9 --- /dev/null +++ b/StoneIsland/plugins/cordova-plugin-firebasex/src/android/FirebasePlugin.java @@ -0,0 +1,2441 @@ +package org.apache.cordova.firebase; + +import android.app.Activity; +import android.app.NotificationManager; +import android.app.NotificationChannel; +import android.content.ContentResolver; +import android.content.SharedPreferences; +import android.content.pm.PackageManager; +import android.media.RingtoneManager; +import android.net.Uri; +import android.media.AudioAttributes; +import android.content.Context; +import android.content.Intent; +import android.os.Build; +import android.os.Bundle; + +import androidx.annotation.NonNull; +import androidx.core.app.NotificationCompat; +import androidx.core.app.NotificationManagerCompat; + +import android.util.Base64; +import android.util.Log; + +import com.google.firebase.crashlytics.FirebaseCrashlytics; + +import com.google.android.gms.auth.api.Auth; +import com.google.android.gms.auth.api.signin.GoogleSignIn; +import com.google.android.gms.auth.api.signin.GoogleSignInAccount; +import com.google.android.gms.auth.api.signin.GoogleSignInClient; +import com.google.android.gms.auth.api.signin.GoogleSignInOptions; +import com.google.android.gms.common.api.ApiException; +import com.google.android.gms.common.api.CommonStatusCodes; +import com.google.android.gms.common.api.GoogleApiClient; +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.FirebaseApp; +import com.google.firebase.analytics.FirebaseAnalytics; +import com.google.firebase.auth.AuthCredential; +import com.google.firebase.auth.AuthResult; +import com.google.firebase.auth.FirebaseAuth; +import com.google.firebase.auth.FirebaseUser; +import com.google.firebase.auth.GetTokenResult; +import com.google.firebase.auth.GoogleAuthProvider; +import com.google.firebase.auth.OAuthProvider; +import com.google.firebase.auth.UserProfileChangeRequest; +import com.google.firebase.firestore.CollectionReference; +import com.google.firebase.firestore.DocumentReference; +import com.google.firebase.firestore.DocumentSnapshot; +import com.google.firebase.firestore.FirebaseFirestore; +import com.google.firebase.firestore.Query; +import com.google.firebase.firestore.QueryDocumentSnapshot; +import com.google.firebase.firestore.QuerySnapshot; +import com.google.firebase.firestore.Query.Direction; +import com.google.firebase.iid.FirebaseInstanceId; +import com.google.firebase.messaging.FirebaseMessaging; +import com.google.firebase.remoteconfig.FirebaseRemoteConfig; +import com.google.firebase.remoteconfig.FirebaseRemoteConfigInfo; +import com.google.firebase.remoteconfig.FirebaseRemoteConfigSettings; +import com.google.firebase.remoteconfig.FirebaseRemoteConfigValue; +import com.google.firebase.perf.FirebasePerformance; +import com.google.firebase.perf.metrics.Trace; + + +import org.apache.cordova.CallbackContext; +import org.apache.cordova.CordovaInterface; +import org.apache.cordova.CordovaPlugin; +import org.apache.cordova.PluginResult; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Objects; +import java.util.Random; +import java.util.Set; +import java.util.List; + +// Firebase PhoneAuth +import java.util.concurrent.TimeUnit; + +import com.google.firebase.FirebaseException; +import com.google.firebase.auth.FirebaseAuthInvalidCredentialsException; +import com.google.firebase.FirebaseTooManyRequestsException; +import com.google.firebase.auth.PhoneAuthCredential; +import com.google.firebase.auth.PhoneAuthProvider; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; + +import static android.content.Context.MODE_PRIVATE; + +public class FirebasePlugin extends CordovaPlugin { + + protected static FirebasePlugin instance = null; + private FirebaseAnalytics mFirebaseAnalytics; + private FirebaseCrashlytics firebaseCrashlytics; + private FirebaseFirestore firestore; + private Gson gson; + private FirebaseAuth.AuthStateListener authStateListener; + private boolean authStateChangeListenerInitialized = false; + private static CordovaInterface cordovaInterface = null; + protected static Context applicationContext = null; + private static Activity cordovaActivity = null; + + protected static final String TAG = "FirebasePlugin"; + protected static final String JS_GLOBAL_NAMESPACE = "FirebasePlugin."; + protected static final String KEY = "badge"; + protected static final int GOOGLE_SIGN_IN = 0x1; + protected static final String SETTINGS_NAME = "settings"; + private static final String CRASHLYTICS_COLLECTION_ENABLED = "firebase_crashlytics_collection_enabled"; + private static final String ANALYTICS_COLLECTION_ENABLED = "firebase_analytics_collection_enabled"; + private static final String PERFORMANCE_COLLECTION_ENABLED = "firebase_performance_collection_enabled"; + + private static boolean inBackground = true; + private static ArrayList<Bundle> notificationStack = null; + private static CallbackContext notificationCallbackContext; + private static CallbackContext tokenRefreshCallbackContext; + private static CallbackContext activityResultCallbackContext; + private static CallbackContext authResultCallbackContext; + + private static NotificationChannel defaultNotificationChannel = null; + public static String defaultChannelId = null; + public static String defaultChannelName = null; + + private Map<String, AuthCredential> authCredentials = new HashMap<String, AuthCredential>(); + private Map<String, OAuthProvider> authProviders = new HashMap<String, OAuthProvider>(); + + @Override + protected void pluginInitialize() { + instance = this; + cordovaActivity = this.cordova.getActivity(); + applicationContext = cordovaActivity.getApplicationContext(); + final Bundle extras = cordovaActivity.getIntent().getExtras(); + FirebasePlugin.cordovaInterface = this.cordova; + firebaseCrashlytics = FirebaseCrashlytics.getInstance(); + this.cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + Log.d(TAG, "Starting Firebase plugin"); + + if(getMetaDataFromManifest(CRASHLYTICS_COLLECTION_ENABLED)){ + setPreference(CRASHLYTICS_COLLECTION_ENABLED, true); + } + + if(getMetaDataFromManifest(ANALYTICS_COLLECTION_ENABLED)){ + setPreference(ANALYTICS_COLLECTION_ENABLED, true); + } + + if(getMetaDataFromManifest(PERFORMANCE_COLLECTION_ENABLED)){ + setPreference(PERFORMANCE_COLLECTION_ENABLED, true); + } + + FirebaseApp.initializeApp(applicationContext); + mFirebaseAnalytics = FirebaseAnalytics.getInstance(applicationContext); + + authStateListener = new AuthStateListener(); + FirebaseAuth.getInstance().addAuthStateListener(authStateListener); + + firestore = FirebaseFirestore.getInstance(); + gson = new Gson(); + + if (extras != null && extras.size() > 1) { + if (FirebasePlugin.notificationStack == null) { + FirebasePlugin.notificationStack = new ArrayList<Bundle>(); + } + if (extras.containsKey("google.message_id")) { + extras.putString("messageType", "notification"); + extras.putString("tap", "background"); + notificationStack.add(extras); + Log.d(TAG, "Notification message found on init: " + extras.toString()); + } + } + defaultChannelId = getStringResource("default_notification_channel_id"); + defaultChannelName = getStringResource("default_notification_channel_name"); + createDefaultChannel(); + }catch (Exception e){ + handleExceptionWithoutContext(e); + } + } + }); + } + + @Override + public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException { + try{ + if (action.equals("getId")) { + this.getId(callbackContext); + return true; + } else if (action.equals("getToken")) { + this.getToken(callbackContext); + return true; + } else if (action.equals("hasPermission")) { + this.hasPermission(callbackContext); + return true; + }else if (action.equals("subscribe")) { + this.subscribe(callbackContext, args.getString(0)); + return true; + } else if (action.equals("unsubscribe")) { + this.unsubscribe(callbackContext, args.getString(0)); + return true; + } else if (action.equals("isAutoInitEnabled")) { + isAutoInitEnabled(callbackContext); + return true; + } else if (action.equals("setAutoInitEnabled")) { + setAutoInitEnabled(callbackContext, args.getBoolean(0)); + return true; + } else if (action.equals("unregister")) { + this.unregister(callbackContext); + return true; + } else if (action.equals("onMessageReceived")) { + this.onMessageReceived(callbackContext); + return true; + } else if (action.equals("onTokenRefresh")) { + this.onTokenRefresh(callbackContext); + return true; + } else if (action.equals("logEvent")) { + this.logEvent(callbackContext, args.getString(0), args.getJSONObject(1)); + return true; + } else if (action.equals("logError")) { + this.logError(callbackContext, args); + return true; + }else if(action.equals("setCrashlyticsUserId")){ + this.setCrashlyticsUserId(callbackContext, args.getString(0)); + return true; + } else if (action.equals("setScreenName")) { + this.setScreenName(callbackContext, args.getString(0)); + return true; + } else if (action.equals("setUserId")) { + this.setUserId(callbackContext, args.getString(0)); + return true; + } else if (action.equals("setUserProperty")) { + this.setUserProperty(callbackContext, args.getString(0), args.getString(1)); + return true; + } else if (action.equals("activateFetched")) { + this.activateFetched(callbackContext); + return true; + } else if (action.equals("fetch")) { + if (args.length() > 0) { + this.fetch(callbackContext, args.getLong(0)); + } else { + this.fetch(callbackContext); + } + return true; + } else if (action.equals("getByteArray")) { + this.getByteArray(callbackContext, args.getString(0)); + return true; + } else if (action.equals("getValue")) { + this.getValue(callbackContext, args.getString(0)); + return true; + } else if (action.equals("getInfo")) { + this.getInfo(callbackContext); + return true; + } else if (action.equals("setConfigSettings")) { + this.setConfigSettings(callbackContext, args.getJSONObject(0)); + return true; + } else if (action.equals("setDefaults")) { + this.setDefaults(callbackContext, args.getJSONObject(0)); + return true; + } else if (action.equals("verifyPhoneNumber")) { + this.verifyPhoneNumber(callbackContext, args); + return true; + } else if (action.equals("authenticateUserWithGoogle")) { + this.authenticateUserWithGoogle(callbackContext, args); + return true; + } else if (action.equals("authenticateUserWithApple")) { + this.authenticateUserWithApple(callbackContext, args); + return true; + } else if (action.equals("createUserWithEmailAndPassword")) { + this.createUserWithEmailAndPassword(callbackContext, args); + return true; + } else if (action.equals("signInUserWithEmailAndPassword")) { + this.signInUserWithEmailAndPassword(callbackContext, args); + return true; + } else if (action.equals("signInUserWithCustomToken")) { + this.signInUserWithCustomToken(callbackContext, args); + return true; + } else if (action.equals("signInUserAnonymously")) { + this.signInUserAnonymously(callbackContext); + return true; + } else if (action.equals("signInWithCredential")) { + this.signInWithCredential(callbackContext, args); + return true; + } else if (action.equals("linkUserWithCredential")) { + this.linkUserWithCredential(callbackContext, args); + return true; + } else if (action.equals("reauthenticateWithCredential")) { + this.reauthenticateWithCredential(callbackContext, args); + return true; + } else if (action.equals("isUserSignedIn")) { + this.isUserSignedIn(callbackContext, args); + return true; + } else if (action.equals("signOutUser")) { + this.signOutUser(callbackContext, args); + return true; + } else if (action.equals("getCurrentUser")) { + this.getCurrentUser(callbackContext, args); + return true; + } else if (action.equals("reloadCurrentUser")) { + this.reloadCurrentUser(callbackContext, args); + return true; + } else if (action.equals("updateUserProfile")) { + this.updateUserProfile(callbackContext, args); + return true; + } else if (action.equals("updateUserEmail")) { + this.updateUserEmail(callbackContext, args); + return true; + } else if (action.equals("sendUserEmailVerification")) { + this.sendUserEmailVerification(callbackContext, args); + return true; + } else if (action.equals("updateUserPassword")) { + this.updateUserPassword(callbackContext, args); + return true; + } else if (action.equals("sendUserPasswordResetEmail")) { + this.sendUserPasswordResetEmail(callbackContext, args); + return true; + } else if (action.equals("deleteUser")) { + this.deleteUser(callbackContext, args); + return true; + } else if (action.equals("startTrace")) { + this.startTrace(callbackContext, args.getString(0)); + return true; + } else if (action.equals("incrementCounter")) { + this.incrementCounter(callbackContext, args.getString(0), args.getString(1)); + return true; + } else if (action.equals("stopTrace")) { + this.stopTrace(callbackContext, args.getString(0)); + return true; + } else if (action.equals("setAnalyticsCollectionEnabled")) { + this.setAnalyticsCollectionEnabled(callbackContext, args.getBoolean(0)); + return true; + } else if (action.equals("isAnalyticsCollectionEnabled")) { + this.isAnalyticsCollectionEnabled(callbackContext); + return true; + } else if (action.equals("setPerformanceCollectionEnabled")) { + this.setPerformanceCollectionEnabled(callbackContext, args.getBoolean(0)); + return true; + } else if (action.equals("isPerformanceCollectionEnabled")) { + this.isPerformanceCollectionEnabled(callbackContext); + return true; + } else if (action.equals("setCrashlyticsCollectionEnabled")) { + this.setCrashlyticsCollectionEnabled(callbackContext, args.getBoolean(0)); + return true; + } else if (action.equals("isCrashlyticsCollectionEnabled")) { + this.isCrashlyticsCollectionEnabled(callbackContext); + return true; + } else if (action.equals("clearAllNotifications")) { + this.clearAllNotifications(callbackContext); + return true; + } else if (action.equals("logMessage")) { + logMessage(args, callbackContext); + return true; + } else if (action.equals("sendCrash")) { + sendCrash(args, callbackContext); + return true; + } else if (action.equals("createChannel")) { + this.createChannel(callbackContext, args.getJSONObject(0)); + return true; + } else if (action.equals("deleteChannel")) { + this.deleteChannel(callbackContext, args.getString(0)); + return true; + } else if (action.equals("listChannels")) { + this.listChannels(callbackContext); + return true; + } else if (action.equals("setDefaultChannel")) { + this.setDefaultChannel(callbackContext, args.getJSONObject(0)); + return true; + } else if (action.equals("addDocumentToFirestoreCollection")) { + this.addDocumentToFirestoreCollection(args, callbackContext); + return true; + } else if (action.equals("setDocumentInFirestoreCollection")) { + this.setDocumentInFirestoreCollection(args, callbackContext); + return true; + } else if (action.equals("updateDocumentInFirestoreCollection")) { + this.updateDocumentInFirestoreCollection(args, callbackContext); + return true; + } else if (action.equals("deleteDocumentFromFirestoreCollection")) { + this.deleteDocumentFromFirestoreCollection(args, callbackContext); + return true; + } else if (action.equals("documentExistsInFirestoreCollection")) { + this.documentExistsInFirestoreCollection(args, callbackContext); + return true; + } else if (action.equals("fetchDocumentInFirestoreCollection")) { + this.fetchDocumentInFirestoreCollection(args, callbackContext); + return true; + } else if (action.equals("fetchFirestoreCollection")) { + this.fetchFirestoreCollection(args, callbackContext); + return true; + } else if (action.equals("grantPermission") + || action.equals("setBadgeNumber") + || action.equals("getBadgeNumber") + ) { + // Stubs for other platform methods + callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, true)); + return true; + }else{ + callbackContext.error("Invalid action: " + action); + return false; + } + }catch(Exception e){ + handleExceptionWithContext(e, callbackContext); + } + return false; + } + + @Override + public void onPause(boolean multitasking) { + FirebasePlugin.inBackground = true; + } + + @Override + public void onResume(boolean multitasking) { + FirebasePlugin.inBackground = false; + } + + @Override + public void onReset() { + FirebasePlugin.notificationCallbackContext = null; + FirebasePlugin.tokenRefreshCallbackContext = null; + FirebasePlugin.activityResultCallbackContext = null; + FirebasePlugin.authResultCallbackContext = null; + } + + @Override + public void onDestroy() { + FirebaseAuth.getInstance().removeAuthStateListener(authStateListener); + instance = null; + cordovaActivity = null; + cordovaInterface = null; + applicationContext = null; + super.onDestroy(); + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + try { + switch (requestCode) { + case GOOGLE_SIGN_IN: + Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(data); + GoogleSignInAccount acct; + try{ + acct = task.getResult(ApiException.class); + }catch (ApiException ae){ + if(ae.getStatusCode() == 10){ + throw new Exception("Unknown server client ID"); + }else{ + throw new Exception(CommonStatusCodes.getStatusCodeString(ae.getStatusCode())); + } + } + AuthCredential credential = GoogleAuthProvider.getCredential(acct.getIdToken(), null); + String id = FirebasePlugin.instance.saveAuthCredential(credential); + + JSONObject returnResults = new JSONObject(); + returnResults.put("instantVerification", true); + returnResults.put("id", id); + FirebasePlugin.activityResultCallbackContext.success(returnResults); + break; + } + } catch (Exception e) { + handleExceptionWithContext(e, FirebasePlugin.activityResultCallbackContext); + } + } + + /** + * Get a string from resources without importing the .R package + * + * @param name Resource Name + * @return Resource + */ + private String getStringResource(String name) { + return applicationContext.getString( + applicationContext.getResources().getIdentifier( + name, "string", applicationContext.getPackageName() + ) + ); + } + + private void onMessageReceived(final CallbackContext callbackContext) { + FirebasePlugin.notificationCallbackContext = callbackContext; + if (FirebasePlugin.notificationStack != null) { + for (Bundle bundle : FirebasePlugin.notificationStack) { + FirebasePlugin.sendMessage(bundle, applicationContext); + } + FirebasePlugin.notificationStack.clear(); + } + } + + private void onTokenRefresh(final CallbackContext callbackContext) { + FirebasePlugin.tokenRefreshCallbackContext = callbackContext; + + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + String currentToken = FirebaseInstanceId.getInstance().getToken(); + if (currentToken != null) { + FirebasePlugin.sendToken(currentToken); + } + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + }); + } + + public static void sendMessage(Bundle bundle, Context context) { + if (!FirebasePlugin.hasNotificationsCallback()) { + String packageName = context.getPackageName(); + if (FirebasePlugin.notificationStack == null) { + FirebasePlugin.notificationStack = new ArrayList<Bundle>(); + } + notificationStack.add(bundle); + + return; + } + + final CallbackContext callbackContext = FirebasePlugin.notificationCallbackContext; + if(bundle != null){ + // Pass the message bundle to the receiver manager so any registered receivers can decide to handle it + boolean wasHandled = FirebasePluginMessageReceiverManager.sendMessage(bundle); + if (wasHandled) { + Log.d(TAG, "Message bundle was handled by a registered receiver"); + }else if (callbackContext != null) { + JSONObject json = new JSONObject(); + Set<String> keys = bundle.keySet(); + for (String key : keys) { + try { + json.put(key, bundle.get(key)); + } catch (JSONException e) { + handleExceptionWithContext(e, callbackContext); + return; + } + } + + PluginResult pluginresult = new PluginResult(PluginResult.Status.OK, json); + pluginresult.setKeepCallback(true); + callbackContext.sendPluginResult(pluginresult); + } + } + } + + public static void sendToken(String token) { + if (FirebasePlugin.tokenRefreshCallbackContext == null) { + return; + } + + final CallbackContext callbackContext = FirebasePlugin.tokenRefreshCallbackContext; + if (callbackContext != null && token != null) { + PluginResult pluginresult = new PluginResult(PluginResult.Status.OK, token); + pluginresult.setKeepCallback(true); + callbackContext.sendPluginResult(pluginresult); + } + } + + public static boolean inBackground() { + return FirebasePlugin.inBackground; + } + + public static boolean hasNotificationsCallback() { + return FirebasePlugin.notificationCallbackContext != null; + } + + @Override + public void onNewIntent(Intent intent) { + try { + super.onNewIntent(intent); + final Bundle data = intent.getExtras(); + if (data != null && data.containsKey("google.message_id")) { + data.putString("messageType", "notification"); + data.putString("tap", "background"); + Log.d(TAG, "Notification message on new intent: " + data.toString()); + FirebasePlugin.sendMessage(data, applicationContext); + } + }catch (Exception e){ + handleExceptionWithoutContext(e); + } + } + + + private void getId(final CallbackContext callbackContext) { + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + String id = FirebaseInstanceId.getInstance().getId(); + callbackContext.success(id); + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + }); + } + + private void getToken(final CallbackContext callbackContext) { + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + String token = FirebaseInstanceId.getInstance().getToken(); + callbackContext.success(token); + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + }); + } + + private void hasPermission(final CallbackContext callbackContext) { + if(cordovaActivity == null) return; + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + NotificationManagerCompat notificationManagerCompat = NotificationManagerCompat.from(cordovaActivity); + boolean areNotificationsEnabled = notificationManagerCompat.areNotificationsEnabled(); + callbackContext.success(areNotificationsEnabled ? 1 : 0); + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + }); + } + + private void subscribe(final CallbackContext callbackContext, final String topic) { + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + handleTaskOutcome(FirebaseMessaging.getInstance().subscribeToTopic(topic), callbackContext); + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + }); + } + + private void unsubscribe(final CallbackContext callbackContext, final String topic) { + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + handleTaskOutcome(FirebaseMessaging.getInstance().unsubscribeFromTopic(topic), callbackContext); + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + }); + } + + private void unregister(final CallbackContext callbackContext) { + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + FirebaseInstanceId.getInstance().deleteInstanceId(); + callbackContext.success(); + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + }); + } + + private void isAutoInitEnabled(final CallbackContext callbackContext) { + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + boolean isEnabled = FirebaseMessaging.getInstance().isAutoInitEnabled(); + callbackContext.success(isEnabled ? 1 : 0); + } catch (Exception e) { + logExceptionToCrashlytics(e); + callbackContext.error(e.getMessage()); + } + } + }); + } + + private void setAutoInitEnabled(final CallbackContext callbackContext, final boolean enabled) { + final FirebasePlugin self = this; + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + FirebaseMessaging.getInstance().setAutoInitEnabled(enabled); + callbackContext.success(); + } catch (Exception e) { + logExceptionToCrashlytics(e); + e.printStackTrace(); + callbackContext.error(e.getMessage()); + } + } + }); + } + + private void logEvent(final CallbackContext callbackContext, final String name, final JSONObject params) + throws JSONException { + final Bundle bundle = new Bundle(); + Iterator iter = params.keys(); + while (iter.hasNext()) { + String key = (String) iter.next(); + Object value = params.get(key); + + if (value instanceof Integer || value instanceof Double) { + bundle.putFloat(key, ((Number) value).floatValue()); + } else { + bundle.putString(key, value.toString()); + } + } + + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + mFirebaseAnalytics.logEvent(name, bundle); + callbackContext.success(); + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + }); + } + + private void logError(final CallbackContext callbackContext, final JSONArray args) throws JSONException { + final String message = args.getString(0); + + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + if(isCrashlyticsEnabled()) { + // We can optionally be passed a stack trace generated by stacktrace.js. + if (args.length() == 2) { + JSONArray stackTrace = args.getJSONArray(1); + StackTraceElement[] trace = new StackTraceElement[stackTrace.length()]; + for (int i = 0; i < stackTrace.length(); i++) { + JSONObject elem = stackTrace.getJSONObject(i); + trace[i] = new StackTraceElement( + "", + elem.optString("functionName", "(anonymous function)"), + elem.optString("fileName", "(unknown file)"), + elem.optInt("lineNumber", -1) + ); + } + + Exception e = new JavaScriptException(message); + e.setStackTrace(trace); + logExceptionToCrashlytics(e); + } else { + logExceptionToCrashlytics(new JavaScriptException(message)); + } + + Log.e(TAG, message); + callbackContext.success(1); + }else{ + callbackContext.error("Cannot log error - Crashlytics collection is disabled"); + } + } catch (Exception e) { + logExceptionToCrashlytics(e); + callbackContext.error(e.getMessage()); + } + } + }); + } + + private void logMessage(final JSONArray data, + final CallbackContext callbackContext) { + + if(isCrashlyticsEnabled()){ + String message = data.optString(0); + logMessageToCrashlytics(message); + callbackContext.success(); + }else{ + callbackContext.error("Cannot log message - Crashlytics collection is disabled"); + } + } + + private void sendCrash(final JSONArray data, + final CallbackContext callbackContext) { + + cordovaActivity.runOnUiThread(new Runnable() { + @Override + public void run() { + throw new RuntimeException("This is a crash"); + } + }); + } + + + private void setCrashlyticsUserId(final CallbackContext callbackContext, final String userId) { + cordovaActivity.runOnUiThread(new Runnable() { + public void run() { + try { + if(isCrashlyticsEnabled()){ + firebaseCrashlytics.setUserId(userId); + callbackContext.success(); + }else{ + callbackContext.error("Cannot set Crashlytics user ID - Crashlytics collection is disabled"); + } + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + }); + } + + private void setScreenName(final CallbackContext callbackContext, final String name) { + // This must be called on the main thread + cordovaActivity.runOnUiThread(new Runnable() { + public void run() { + try { + mFirebaseAnalytics.setCurrentScreen(cordovaActivity, name, null); + callbackContext.success(); + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + }); + } + + private void setUserId(final CallbackContext callbackContext, final String id) { + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + mFirebaseAnalytics.setUserId(id); + callbackContext.success(); + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + }); + } + + private void setUserProperty(final CallbackContext callbackContext, final String name, final String value) { + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + mFirebaseAnalytics.setUserProperty(name, value); + callbackContext.success(); + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + }); + } + + private void activateFetched(final CallbackContext callbackContext) { + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + final boolean activated = FirebaseRemoteConfig.getInstance().activateFetched(); + callbackContext.success(String.valueOf(activated)); + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + }); + } + + private void fetch(CallbackContext callbackContext) { + fetch(callbackContext, FirebaseRemoteConfig.getInstance().fetch()); + } + + private void fetch(CallbackContext callbackContext, long cacheExpirationSeconds) { + fetch(callbackContext, FirebaseRemoteConfig.getInstance().fetch(cacheExpirationSeconds)); + } + + private void fetch(final CallbackContext callbackContext, final Task<Void> task) { + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + handleTaskOutcome(task, callbackContext); + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + }); + } + + private void getByteArray(final CallbackContext callbackContext, final String key) { + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + byte[] bytes = FirebaseRemoteConfig.getInstance().getByteArray(key); + JSONObject object = new JSONObject(); + object.put("base64", Base64.encodeToString(bytes, Base64.DEFAULT)); + object.put("array", new JSONArray(bytes)); + callbackContext.success(object); + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + }); + } + + private void getValue(final CallbackContext callbackContext, final String key) { + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + FirebaseRemoteConfigValue value = FirebaseRemoteConfig.getInstance().getValue(key); + callbackContext.success(value.asString()); + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + }); + } + + private void getInfo(final CallbackContext callbackContext) { + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + FirebaseRemoteConfigInfo remoteConfigInfo = FirebaseRemoteConfig.getInstance().getInfo(); + JSONObject info = new JSONObject(); + + JSONObject settings = new JSONObject(); + settings.put("developerModeEnabled", remoteConfigInfo.getConfigSettings().isDeveloperModeEnabled()); + info.put("configSettings", settings); + + info.put("fetchTimeMillis", remoteConfigInfo.getFetchTimeMillis()); + info.put("lastFetchStatus", remoteConfigInfo.getLastFetchStatus()); + + callbackContext.success(info); + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + }); + } + + private void setConfigSettings(final CallbackContext callbackContext, final JSONObject config) { + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + boolean devMode = config.getBoolean("developerModeEnabled"); + FirebaseRemoteConfigSettings.Builder settings = new FirebaseRemoteConfigSettings.Builder() + .setDeveloperModeEnabled(devMode); + FirebaseRemoteConfig.getInstance().setConfigSettings(settings.build()); + callbackContext.success(); + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + }); + } + + private void setDefaults(final CallbackContext callbackContext, final JSONObject defaults) { + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + FirebaseRemoteConfig.getInstance().setDefaults(defaultsToMap(defaults)); + callbackContext.success(); + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + }); + } + + private static Map<String, Object> defaultsToMap(JSONObject object) throws JSONException { + final Map<String, Object> map = new HashMap<String, Object>(); + + for (Iterator<String> keys = object.keys(); keys.hasNext(); ) { + String key = keys.next(); + Object value = object.get(key); + + if (value instanceof Integer) { + //setDefaults() should take Longs + value = new Long((Integer) value); + } else if (value instanceof JSONArray) { + JSONArray array = (JSONArray) value; + if (array.length() == 1 && array.get(0) instanceof String) { + //parse byte[] as Base64 String + value = Base64.decode(array.getString(0), Base64.DEFAULT); + } else { + //parse byte[] as numeric array + byte[] bytes = new byte[array.length()]; + for (int i = 0; i < array.length(); i++) + bytes[i] = (byte) array.getInt(i); + value = bytes; + } + } + + map.put(key, value); + } + return map; + } + + + public void isUserSignedIn(final CallbackContext callbackContext, final JSONArray args){ + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + boolean isSignedIn = FirebaseAuth.getInstance().getCurrentUser() != null; + callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, isSignedIn)); + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + }); + } + + public void signOutUser(final CallbackContext callbackContext, final JSONArray args){ + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser(); + if(user == null){ + callbackContext.error("No user is currently signed"); + return; + } + // Sign out of Firebase + FirebaseAuth.getInstance().signOut(); + + // Try to sign out of Google + try{ + GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN).build(); + GoogleSignInClient mGoogleSignInClient = GoogleSignIn.getClient(cordovaActivity, gso); + handleTaskOutcome(mGoogleSignInClient.signOut(), callbackContext); + }catch(Exception googleSignOutException){ + callbackContext.success(); + } + + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + }); + } + + public void getCurrentUser(final CallbackContext callbackContext, final JSONArray args){ + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser(); + if(user == null){ + callbackContext.error("No user is currently signed"); + return; + } + extractAndReturnUserInfo(callbackContext); + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + }); + } + + public void reloadCurrentUser(final CallbackContext callbackContext, final JSONArray args){ + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser(); + if(user == null){ + callbackContext.error("No user is currently signed"); + return; + } + user.reload() + .addOnSuccessListener(new OnSuccessListener<Void>() { + @Override + public void onSuccess(Void aVoid) { + try { + extractAndReturnUserInfo(callbackContext); + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + }); + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + }); + } + + private void extractAndReturnUserInfo(final CallbackContext callbackContext) throws Exception{ + FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser(); + JSONObject returnResults = new JSONObject(); + returnResults.put("name", user.getDisplayName()); + returnResults.put("email", user.getEmail()); + returnResults.put("emailIsVerified", user.isEmailVerified()); + returnResults.put("phoneNumber", user.getPhoneNumber()); + returnResults.put("photoUrl", user.getPhotoUrl() == null ? null : user.getPhotoUrl().toString()); + returnResults.put("uid", user.getUid()); + returnResults.put("providerId", user.getIdToken(false).getResult().getSignInProvider()); + returnResults.put("isAnonymous", user.isAnonymous()); + + user.getIdToken(true).addOnSuccessListener(new OnSuccessListener<GetTokenResult>() { + @Override + public void onSuccess(GetTokenResult result) { + try { + String idToken = result.getToken(); + returnResults.put("idToken", idToken); + callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, returnResults)); + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + }); + } + + public void updateUserProfile(final CallbackContext callbackContext, final JSONArray args){ + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser(); + if(user == null){ + callbackContext.error("No user is currently signed"); + return; + } + + JSONObject profile = args.getJSONObject(0); + UserProfileChangeRequest profileUpdates; + if(profile.has("name") && profile.has("photoUri")){ + profileUpdates = new UserProfileChangeRequest.Builder() + .setDisplayName(profile.getString("name")) + .setPhotoUri(Uri.parse(profile.getString("photoUri"))) + .build(); + }else if(profile.has("name")){ + profileUpdates = new UserProfileChangeRequest.Builder() + .setDisplayName(profile.getString("name")) + .build(); + }else if(profile.has("photoUri")){ + profileUpdates = new UserProfileChangeRequest.Builder() + .setPhotoUri(Uri.parse(profile.getString("photoUri"))) + .build(); + }else{ + callbackContext.error("'name' and/or 'photoUri' keys must be specified in the profile object"); + return; + } + + handleTaskOutcome(user.updateProfile(profileUpdates), callbackContext); + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + }); + } + + public void updateUserEmail(final CallbackContext callbackContext, final JSONArray args){ + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser(); + if(user == null){ + callbackContext.error("No user is currently signed"); + return; + } + + String email = args.getString(0); + handleTaskOutcome(user.updateEmail(email), callbackContext); + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + }); + } + + public void sendUserEmailVerification(final CallbackContext callbackContext, final JSONArray args){ + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser(); + if(user == null){ + callbackContext.error("No user is currently signed"); + return; + } + + handleTaskOutcome(user.sendEmailVerification(), callbackContext); + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + }); + } + + public void updateUserPassword(final CallbackContext callbackContext, final JSONArray args){ + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser(); + if(user == null){ + callbackContext.error("No user is currently signed"); + return; + } + + String password = args.getString(0); + handleTaskOutcome(user.updatePassword(password), callbackContext); + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + }); + } + + public void sendUserPasswordResetEmail(final CallbackContext callbackContext, final JSONArray args){ + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + FirebaseAuth auth = FirebaseAuth.getInstance(); + String email = args.getString(0); + handleTaskOutcome(auth.sendPasswordResetEmail(email), callbackContext); + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + }); + } + + public void deleteUser(final CallbackContext callbackContext, final JSONArray args){ + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser(); + if(user == null){ + callbackContext.error("No user is currently signed"); + return; + } + handleTaskOutcome(user.delete(), callbackContext); + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + }); + } + + public void reauthenticateWithCredential(final CallbackContext callbackContext, final JSONArray args){ + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser(); + if(user == null){ + callbackContext.error("No user is currently signed"); + return; + } + + JSONObject jsonCredential = args.getJSONObject(0); + if(!FirebasePlugin.instance.isValidJsonCredential(jsonCredential)){ + callbackContext.error("No auth credentials specified"); + return; + } + + AuthCredential authCredential = FirebasePlugin.instance.obtainAuthCredential(jsonCredential); + if(authCredential != null){ + handleTaskOutcome(user.reauthenticate(authCredential), callbackContext); + return; + } + + OAuthProvider authProvider = FirebasePlugin.instance.obtainAuthProvider(jsonCredential); + if(authProvider != null){ + FirebasePlugin.instance.authResultCallbackContext = callbackContext; + user.startActivityForReauthenticateWithProvider(FirebasePlugin.cordovaActivity, authProvider) + .addOnSuccessListener(new AuthResultOnSuccessListener()) + .addOnFailureListener(new AuthResultOnFailureListener()); + return; + } + + //ELSE + callbackContext.error("Specified native auth credential id does not exist"); + + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + }); + } + + + + public void signInWithCredential(final CallbackContext callbackContext, final JSONArray args){ + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + JSONObject jsonCredential = args.getJSONObject(0); + if(!FirebasePlugin.instance.isValidJsonCredential(jsonCredential)){ + callbackContext.error("No auth credentials specified"); + return; + } + + AuthCredential authCredential = FirebasePlugin.instance.obtainAuthCredential(jsonCredential); + if(authCredential != null){ + FirebaseAuth.getInstance().signInWithCredential(authCredential).addOnCompleteListener(cordova.getActivity(), new AuthResultOnCompleteListener(callbackContext)); + return; + } + + OAuthProvider authProvider = FirebasePlugin.instance.obtainAuthProvider(jsonCredential); + if(authProvider != null){ + FirebasePlugin.instance.authResultCallbackContext = callbackContext; + FirebaseAuth.getInstance().startActivityForSignInWithProvider(FirebasePlugin.cordovaActivity, authProvider) + .addOnSuccessListener(new AuthResultOnSuccessListener()) + .addOnFailureListener(new AuthResultOnFailureListener()); + return; + } + + //ELSE + callbackContext.error("Specified native auth credential id does not exist"); + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + }); + } + + public void linkUserWithCredential(final CallbackContext callbackContext, final JSONArray args){ + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + JSONObject jsonCredential = args.getJSONObject(0); + if(!FirebasePlugin.instance.isValidJsonCredential(jsonCredential)){ + callbackContext.error("No auth credentials specified"); + return; + } + + AuthCredential authCredential = FirebasePlugin.instance.obtainAuthCredential(jsonCredential); + if(authCredential != null){ + FirebaseAuth.getInstance().getCurrentUser().linkWithCredential(authCredential).addOnCompleteListener(cordova.getActivity(), new AuthResultOnCompleteListener(callbackContext)); + return; + } + + //ELSE + callbackContext.error("Specified native auth credential id does not exist"); + + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + }); + } + + private boolean isValidJsonCredential(JSONObject jsonCredential) throws JSONException{ + return jsonCredential.has("id") || (jsonCredential.has("verificationId") && jsonCredential.has("code")); + } + + private PhoneAuthProvider.OnVerificationStateChangedCallbacks mCallbacks; + + public void verifyPhoneNumber( + final CallbackContext callbackContext, + final JSONArray args + ) { + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + mCallbacks = new PhoneAuthProvider.OnVerificationStateChangedCallbacks() { + @Override + public void onVerificationCompleted(PhoneAuthCredential credential) { + // This callback will be invoked in two situations: + // 1 - Instant verification. In some cases the phone number can be instantly + // verified without needing to send or enter a verification code. + // 2 - Auto-retrieval. On some devices Google Play services can automatically + // detect the incoming verification SMS and perform verificaiton without + // user action. + Log.d(TAG, "success: verifyPhoneNumber.onVerificationCompleted"); + + String id = FirebasePlugin.instance.saveAuthCredential((AuthCredential) credential); + + JSONObject returnResults = new JSONObject(); + try { + returnResults.put("instantVerification", true); + returnResults.put("id", id); + } catch(JSONException e){ + handleExceptionWithContext(e, callbackContext); + return; + } + PluginResult pluginresult = new PluginResult(PluginResult.Status.OK, returnResults); + pluginresult.setKeepCallback(true); + callbackContext.sendPluginResult(pluginresult); + } + + @Override + public void onVerificationFailed(FirebaseException e) { + // This callback is invoked in an invalid request for verification is made, + // for instance if the the phone number format is not valid. + Log.w(TAG, "failed: verifyPhoneNumber.onVerificationFailed ", e); + + String errorMsg; + if (e instanceof FirebaseAuthInvalidCredentialsException) { + // Invalid request + errorMsg = "Invalid phone number"; + } else if (e instanceof FirebaseTooManyRequestsException) { + // The SMS quota for the project has been exceeded + errorMsg = "The SMS quota for the project has been exceeded"; + }else{ + errorMsg = e.getMessage(); + } + callbackContext.error(errorMsg); + } + + @Override + public void onCodeSent(String verificationId, PhoneAuthProvider.ForceResendingToken token) { + // The SMS verification code has been sent to the provided phone number, we + // now need to ask the user to enter the code and then construct a credential + // by combining the code with a verification ID [(in app)]. + Log.d(TAG, "success: verifyPhoneNumber.onCodeSent"); + + JSONObject returnResults = new JSONObject(); + try { + returnResults.put("verificationId", verificationId); + returnResults.put("instantVerification", false); + } catch (JSONException e) { + handleExceptionWithContext(e, callbackContext); + return; + } + PluginResult pluginresult = new PluginResult(PluginResult.Status.OK, returnResults); + pluginresult.setKeepCallback(true); + callbackContext.sendPluginResult(pluginresult); + } + }; + + String number = args.getString(0); + int timeOutDuration = args.getInt(1); + String smsCode = args.getString(2); + + if(smsCode != null && smsCode != "null"){ + FirebaseAuth.getInstance().getFirebaseAuthSettings().setAutoRetrievedSmsCodeForPhoneNumber(number, smsCode); + } + + PhoneAuthProvider.getInstance().verifyPhoneNumber(number, // Phone number to verify + timeOutDuration, // Timeout duration + TimeUnit.SECONDS, // Unit of timeout + cordovaActivity, // Activity (for callback binding) + mCallbacks); // OnVerificationStateChangedCallbacks + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + }); + } + + public void createUserWithEmailAndPassword(final CallbackContext callbackContext, final JSONArray args){ + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + String email = args.getString(0); + String password = args.getString(1); + + if(email == null || email.equals("")){ + callbackContext.error("User email address must be specified"); + return; + } + + if(password == null || password.equals("")){ + callbackContext.error("User password must be specified"); + return; + } + + FirebaseAuth.getInstance().createUserWithEmailAndPassword(email, password).addOnCompleteListener(cordova.getActivity(), new AuthResultOnCompleteListener(callbackContext)); + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + }); + } + + public void signInUserWithEmailAndPassword(final CallbackContext callbackContext, final JSONArray args){ + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + String email = args.getString(0); + String password = args.getString(1); + + if(email == null || email.equals("")){ + callbackContext.error("User email address must be specified"); + return; + } + + if(password == null || password.equals("")){ + callbackContext.error("User password must be specified"); + return; + } + + FirebaseAuth.getInstance().signInWithEmailAndPassword(email, password).addOnCompleteListener(cordova.getActivity(), new AuthResultOnCompleteListener(callbackContext)); + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + }); + } + + + public void authenticateUserWithGoogle(final CallbackContext callbackContext, final JSONArray args){ + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + String clientId = args.getString(0); + + GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) + .requestIdToken(clientId) + .requestEmail() + .build(); + + GoogleSignInClient mGoogleSignInClient = GoogleSignIn.getClient(FirebasePlugin.instance.cordovaActivity, gso); + Intent signInIntent = mGoogleSignInClient.getSignInIntent(); + FirebasePlugin.activityResultCallbackContext = callbackContext; + FirebasePlugin.instance.cordovaInterface.startActivityForResult(FirebasePlugin.instance, signInIntent, GOOGLE_SIGN_IN); + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + }); + } + + public void authenticateUserWithApple(final CallbackContext callbackContext, final JSONArray args){ + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + String locale = args.getString(0); + OAuthProvider.Builder provider = OAuthProvider.newBuilder("apple.com"); + if(locale != null){ + provider.addCustomParameter("locale", locale); + } + Task<AuthResult> pending = FirebaseAuth.getInstance().getPendingAuthResult(); + if (pending != null) { + callbackContext.error("Auth result is already pending"); + pending + .addOnSuccessListener(new AuthResultOnSuccessListener()) + .addOnFailureListener(new AuthResultOnFailureListener()); + } else { + String id = FirebasePlugin.instance.saveAuthProvider(provider.build());; + JSONObject returnResults = new JSONObject(); + returnResults.put("instantVerification", true); + returnResults.put("id", id); + callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, returnResults)); + } + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + }); + } + + public void signInUserWithCustomToken(final CallbackContext callbackContext, final JSONArray args){ + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + String customToken = args.getString(0); + + if(customToken == null || customToken.equals("")){ + callbackContext.error("Custom token must be specified"); + return; + } + + FirebaseAuth.getInstance().signInWithCustomToken(customToken).addOnCompleteListener(cordova.getActivity(), new AuthResultOnCompleteListener(callbackContext)); + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + }); + } + + public void signInUserAnonymously(final CallbackContext callbackContext){ + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + FirebaseAuth.getInstance().signInAnonymously().addOnCompleteListener(cordova.getActivity(), new AuthResultOnCompleteListener(callbackContext)); + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + }); + } + + // + // Firebase Performace + // + + private HashMap<String, Trace> traces = new HashMap<String, Trace>(); + + private void startTrace(final CallbackContext callbackContext, final String name) { + final FirebasePlugin self = this; + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + + Trace myTrace = null; + if (self.traces.containsKey(name)) { + myTrace = self.traces.get(name); + } + + if (myTrace == null) { + myTrace = FirebasePerformance.getInstance().newTrace(name); + myTrace.start(); + self.traces.put(name, myTrace); + } + + callbackContext.success(); + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + e.printStackTrace(); + } + } + }); + } + + private void incrementCounter(final CallbackContext callbackContext, final String name, final String counterNamed) { + final FirebasePlugin self = this; + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + + Trace myTrace = null; + if (self.traces.containsKey(name)) { + myTrace = self.traces.get(name); + } + + if (myTrace != null && myTrace instanceof Trace) { + myTrace.incrementMetric(counterNamed, 1); + callbackContext.success(); + } else { + callbackContext.error("Trace not found"); + } + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + e.printStackTrace(); + } + } + }); + } + + private void stopTrace(final CallbackContext callbackContext, final String name) { + final FirebasePlugin self = this; + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + + Trace myTrace = null; + if (self.traces.containsKey(name)) { + myTrace = self.traces.get(name); + } + + if (myTrace != null && myTrace instanceof Trace) { // + myTrace.stop(); + self.traces.remove(name); + callbackContext.success(); + } else { + callbackContext.error("Trace not found"); + } + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + e.printStackTrace(); + } + } + }); + } + + private void setAnalyticsCollectionEnabled(final CallbackContext callbackContext, final boolean enabled) { + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + mFirebaseAnalytics.setAnalyticsCollectionEnabled(enabled); + setPreference(ANALYTICS_COLLECTION_ENABLED, enabled); + callbackContext.success(); + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + e.printStackTrace(); + } + } + }); + } + + private void isAnalyticsCollectionEnabled(final CallbackContext callbackContext) { + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + callbackContext.success(getPreference(ANALYTICS_COLLECTION_ENABLED) ? 1 : 0); + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + e.printStackTrace(); + } + } + }); + } + + private void setPerformanceCollectionEnabled(final CallbackContext callbackContext, final boolean enabled) { + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + FirebasePerformance.getInstance().setPerformanceCollectionEnabled(enabled); + setPreference(PERFORMANCE_COLLECTION_ENABLED, enabled); + callbackContext.success(); + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + e.printStackTrace(); + } + } + }); + } + + private void isPerformanceCollectionEnabled(final CallbackContext callbackContext) { + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + callbackContext.success(getPreference(PERFORMANCE_COLLECTION_ENABLED) ? 1 : 0); + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + e.printStackTrace(); + } + } + }); + } + + private void setCrashlyticsCollectionEnabled(final CallbackContext callbackContext, final boolean enabled) { + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + firebaseCrashlytics.setCrashlyticsCollectionEnabled(enabled); + setPreference(CRASHLYTICS_COLLECTION_ENABLED, enabled); + callbackContext.success(); + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + e.printStackTrace(); + } + } + }); + } + + private void isCrashlyticsCollectionEnabled(final CallbackContext callbackContext) { + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + callbackContext.success(isCrashlyticsEnabled() ? 1 : 0); + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + e.printStackTrace(); + } + } + }); + } + + private boolean isCrashlyticsEnabled(){ + return getPreference(CRASHLYTICS_COLLECTION_ENABLED); + } + + public void clearAllNotifications(final CallbackContext callbackContext) { + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + NotificationManager nm = (NotificationManager) applicationContext.getSystemService(Context.NOTIFICATION_SERVICE); + nm.cancelAll(); + callbackContext.success(); + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + }); + } + + public void createChannel(final CallbackContext callbackContext, final JSONObject options) { + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + createChannel(options); + callbackContext.success(); + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + }); + } + + protected static NotificationChannel createChannel(final JSONObject options) throws JSONException { + NotificationChannel channel = null; + // only call on Android O and above + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + String id = options.getString("id"); + Log.i(TAG, "Creating channel id="+id); + + if(channelExists(id)){ + deleteChannel(id); + } + + NotificationManager nm = (NotificationManager) applicationContext.getSystemService(Context.NOTIFICATION_SERVICE); + String packageName = cordovaActivity.getPackageName(); + + String name = options.optString("name", ""); + Log.d(TAG, "Channel "+id+" - name="+name); + + int importance = options.optInt("importance", NotificationManager.IMPORTANCE_HIGH); + Log.d(TAG, "Channel "+id+" - importance="+importance); + + channel = new NotificationChannel(id, + name, + importance); + + // Description + String description = options.optString("description", ""); + Log.d(TAG, "Channel "+id+" - description="+description); + channel.setDescription(description); + + // Light + boolean light = options.optBoolean("light", true); + Log.d(TAG, "Channel "+id+" - light="+light); + channel.enableLights(light); + + int lightColor = options.optInt("lightColor", -1); + if (lightColor != -1) { + Log.d(TAG, "Channel "+id+" - lightColor="+lightColor); + channel.setLightColor(lightColor); + } + + // Visibility + int visibility = options.optInt("visibility", NotificationCompat.VISIBILITY_PUBLIC); + Log.d(TAG, "Channel "+id+" - visibility="+visibility); + channel.setLockscreenVisibility(visibility); + + // Badge + boolean badge = options.optBoolean("badge", true); + Log.d(TAG, "Channel "+id+" - badge="+badge); + channel.setShowBadge(badge); + + // Sound + String sound = options.optString("sound", "default"); + AudioAttributes audioAttributes = new AudioAttributes.Builder() + .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) + .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE).build(); + if ("ringtone".equals(sound)) { + channel.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE), audioAttributes); + Log.d(TAG, "Channel "+id+" - sound=ringtone"); + } else if (sound != null && !sound.contentEquals("default")) { + Uri soundUri = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + packageName + "/raw/" + sound); + channel.setSound(soundUri, audioAttributes); + Log.d(TAG, "Channel "+id+" - sound="+sound); + } else if (sound != "false"){ + channel.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION), audioAttributes); + Log.d(TAG, "Channel "+id+" - sound=default"); + }else{ + Log.d(TAG, "Channel "+id+" - sound=none"); + } + + // Vibration: if vibration setting is an array set vibration pattern, else set enable vibration. + JSONArray pattern = options.optJSONArray("vibration"); + if (pattern != null) { + int patternLength = pattern.length(); + long[] patternArray = new long[patternLength]; + for (int i = 0; i < patternLength; i++) { + patternArray[i] = pattern.optLong(i); + } + channel.enableVibration(true); + channel.setVibrationPattern(patternArray); + Log.d(TAG, "Channel "+id+" - vibrate="+pattern); + } else { + boolean vibrate = options.optBoolean("vibration", true); + channel.enableVibration(vibrate); + Log.d(TAG, "Channel "+id+" - vibrate="+vibrate); + } + + // Create channel + nm.createNotificationChannel(channel); + } + return channel; + } + + protected static void createDefaultChannel() throws JSONException { + JSONObject options = new JSONObject(); + options.put("id", defaultChannelId); + options.put("name", defaultChannelName); + createDefaultChannel(options); + } + + protected static void createDefaultChannel(final JSONObject options) throws JSONException { + defaultNotificationChannel = createChannel(options); + } + + public void setDefaultChannel(final CallbackContext callbackContext, final JSONObject options) { + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + deleteChannel(defaultChannelId); + + String id = options.optString("id", null); + if(id != null){ + defaultChannelId = id; + } + + String name = options.optString("name", null); + if(name != null){ + defaultChannelName = name; + } + createDefaultChannel(options); + callbackContext.success(); + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + }); + } + + public void deleteChannel(final CallbackContext callbackContext, final String channelID) { + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + deleteChannel(channelID); + callbackContext.success(); + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + }); + } + + protected static void deleteChannel(final String channelID){ + // only call on Android O and above + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + NotificationManager nm = (NotificationManager) applicationContext.getSystemService(Context.NOTIFICATION_SERVICE); + nm.deleteNotificationChannel(channelID); + } + } + + public void listChannels(final CallbackContext callbackContext) { + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + List<NotificationChannel> notificationChannels = listChannels(); + JSONArray channels = new JSONArray(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + for (NotificationChannel notificationChannel : notificationChannels) { + JSONObject channel = new JSONObject(); + channel.put("id", notificationChannel.getId()); + channel.put("name", notificationChannel.getName()); + channels.put(channel); + } + } + callbackContext.success(channels); + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + }); + } + + public static List<NotificationChannel> listChannels(){ + List<NotificationChannel> notificationChannels = null; + // only call on Android O and above + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + NotificationManager nm = (NotificationManager) applicationContext.getSystemService(Context.NOTIFICATION_SERVICE); + notificationChannels = nm.getNotificationChannels(); + } + return notificationChannels; + } + + public static boolean channelExists(String channelId){ + boolean exists = false; + if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){ + List<NotificationChannel> notificationChannels = FirebasePlugin.listChannels(); + if(notificationChannels != null){ + for (NotificationChannel notificationChannel : notificationChannels) { + if(notificationChannel.getId().equals(channelId)){ + exists = true; + } + } + } + } + return exists; + } + + // + // Firestore + // + private void addDocumentToFirestoreCollection(JSONArray args, CallbackContext callbackContext) throws JSONException { + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + String jsonDoc = args.getString(0); + String collection = args.getString(1); + + firestore.collection(collection) + .add(jsonStringToMap(jsonDoc)) + .addOnSuccessListener(new OnSuccessListener<DocumentReference>() { + @Override + public void onSuccess(DocumentReference documentReference) { + callbackContext.success(documentReference.getId()); + } + }) + .addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@NonNull Exception e) { + handleExceptionWithContext(e, callbackContext); + } + }); + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + }); + } + + private void setDocumentInFirestoreCollection(JSONArray args, CallbackContext callbackContext) throws JSONException { + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + String documentId = args.getString(0); + String jsonDoc = args.getString(1); + String collection = args.getString(2); + + firestore.collection(collection).document(documentId) + .set(jsonStringToMap(jsonDoc)) + .addOnSuccessListener(new OnSuccessListener<Void>() { + @Override + public void onSuccess(Void aVoid) { + callbackContext.success(); + } + }) + .addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@NonNull Exception e) { + handleExceptionWithContext(e, callbackContext); + } + }); + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + }); + } + + private void updateDocumentInFirestoreCollection(JSONArray args, CallbackContext callbackContext) throws JSONException { + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + String documentId = args.getString(0); + String jsonDoc = args.getString(1); + String collection = args.getString(2); + + firestore.collection(collection).document(documentId) + .update(jsonStringToMap(jsonDoc)) + .addOnSuccessListener(new OnSuccessListener<Void>() { + @Override + public void onSuccess(Void aVoid) { + callbackContext.success(); + } + }) + .addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@NonNull Exception e) { + handleExceptionWithContext(e, callbackContext); + } + }); + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + }); + } + + private void deleteDocumentFromFirestoreCollection(JSONArray args, CallbackContext callbackContext) throws JSONException { + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + String documentId = args.getString(0); + String collection = args.getString(1); + + firestore.collection(collection).document(documentId) + .delete() + .addOnSuccessListener(new OnSuccessListener<Void>() { + @Override + public void onSuccess(Void aVoid) { + callbackContext.success(); + } + }) + .addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@NonNull Exception e) { + handleExceptionWithContext(e, callbackContext); + } + }); + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + }); + } + + private void documentExistsInFirestoreCollection(JSONArray args, CallbackContext callbackContext) throws JSONException { + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + String documentId = args.getString(0); + String collection = args.getString(1); + + firestore.collection(collection).document(documentId) + .get() + .addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() { + @Override + public void onComplete(@NonNull Task<DocumentSnapshot> task) { + try { + if (task.isSuccessful()) { + DocumentSnapshot document = task.getResult(); + callbackContext.success(document != null && document.getData() != null ? 1 : 0); + } else { + Exception e = task.getException(); + if(e != null){ + handleExceptionWithContext(e, callbackContext); + } + } + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + }) + .addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@NonNull Exception e) { + handleExceptionWithContext(e, callbackContext); + } + }); + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + }); + } + + private void fetchDocumentInFirestoreCollection(JSONArray args, CallbackContext callbackContext) throws JSONException { + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + String documentId = args.getString(0); + String collection = args.getString(1); + + firestore.collection(collection).document(documentId) + .get() + .addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() { + @Override + public void onComplete(@NonNull Task<DocumentSnapshot> task) { + try { + if (task.isSuccessful()) { + DocumentSnapshot document = task.getResult(); + if (document != null && document.getData() != null) { + JSONObject jsonDoc = mapToJsonObject(document.getData()); + callbackContext.success(jsonDoc); + } else { + callbackContext.error("No document found in collection"); + } + } else { + Exception e = task.getException(); + if(e != null){ + handleExceptionWithContext(e, callbackContext); + } + } + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + }) + .addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@NonNull Exception e) { + handleExceptionWithContext(e, callbackContext); + } + }); + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + }); + } + + private void fetchFirestoreCollection(JSONArray args, CallbackContext callbackContext) throws JSONException { + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + String collection = args.getString(0); + JSONArray filters = args.getJSONArray(1); + Query query = firestore.collection(collection); + + for(int i = 0; i < filters.length(); i++) { + JSONArray filter = filters.getJSONArray(i); + switch(filter.getString(0)) { + case "where": + if (Objects.equals(filter.getString(2), new String("=="))) { + query = query.whereEqualTo(filter.getString(1), filter.getString(3)); + } + if (Objects.equals(filter.getString(2), new String("<"))) { + query = query.whereLessThan(filter.getString(1), filter.getString(3)); + } + if (Objects.equals(filter.getString(2), new String(">"))) { + query = query.whereGreaterThan(filter.getString(1), filter.getString(3)); + } + if (Objects.equals(filter.getString(2), new String("<="))) { + query = query.whereLessThanOrEqualTo(filter.getString(1), filter.getString(3)); + } + if (Objects.equals(filter.getString(2), new String(">="))) { + query = query.whereGreaterThanOrEqualTo(filter.getString(1), filter.getString(3)); + } + if (Objects.equals(filter.getString(2), new String("array-contains"))) { + query = query.whereArrayContains(filter.getString(1), filter.getString(3)); + } + break; + case "orderBy": + Direction direction = Direction.ASCENDING; + if (Objects.equals(filter.getString(2), new String("desc"))) { + direction = Direction.DESCENDING; + } + query = query.orderBy(filter.getString(1), direction); + break; + case "startAt": + query = query.startAt(filter.getString(1)); + break; + case "endAt": + query = query.endAt(filter.getString(1)); + break; + case "limit": + query = query.limit(filter.getLong(1)); + break; + } + } + + query.get() + .addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() { + @Override + public void onComplete(@NonNull Task<QuerySnapshot> task) { + try { + if (task.isSuccessful()) { + JSONObject jsonDocs = new JSONObject(); + for (QueryDocumentSnapshot document : task.getResult()) { + jsonDocs.put(document.getId(), mapToJsonObject(document.getData())); + } + callbackContext.success(jsonDocs); + } else { + handleExceptionWithContext(task.getException(), callbackContext); + } + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + }); + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + }); + } + + + protected static void handleExceptionWithContext(Exception e, CallbackContext context) { + String msg = e.toString(); + Log.e(TAG, msg); + instance.logExceptionToCrashlytics(e); + context.error(msg); + } + + protected static void handleExceptionWithoutContext(Exception e){ + String msg = e.toString(); + Log.e(TAG, msg); + if (instance != null) { + instance.logExceptionToCrashlytics(e); + instance.logErrorToWebview(msg); + } + } + + protected void logErrorToWebview(String msg){ + Log.e(TAG, msg); + executeGlobalJavascript("console.error(\""+TAG+"[native]: "+escapeDoubleQuotes(msg)+"\")"); + } + + private String escapeDoubleQuotes(String string){ + String escapedString = string.replace("\"", "\\\""); + escapedString = escapedString.replace("%22", "\\%22"); + return escapedString; + } + + private void executeGlobalJavascript(final String jsString){ + if(cordovaActivity == null) return; + cordovaActivity.runOnUiThread(new Runnable() { + @Override + public void run() { + webView.loadUrl("javascript:" + jsString); + } + }); + } + + private String saveAuthCredential(AuthCredential authCredential){ + String id = this.generateId(); + this.authCredentials.put(id, authCredential); + return id; + } + + private String saveAuthProvider(OAuthProvider authProvider){ + String id = this.generateId(); + this.authProviders.put(id, authProvider); + return id; + } + + private String generateId(){ + Random r = new Random(); + return Integer.toString(r.nextInt(1000+1)); + } + + private boolean getMetaDataFromManifest(String name) throws Exception{ + return applicationContext.getPackageManager().getApplicationInfo(applicationContext.getPackageName(), PackageManager.GET_META_DATA).metaData.getBoolean(name); + } + + private void setPreference(String name, boolean value){ + SharedPreferences settings = cordovaActivity.getSharedPreferences(SETTINGS_NAME, MODE_PRIVATE); + SharedPreferences.Editor editor = settings.edit(); + editor.putBoolean(name, value); + editor.apply(); + } + + private boolean getPreference(String name){ + SharedPreferences settings = cordovaActivity.getSharedPreferences(SETTINGS_NAME, MODE_PRIVATE); + return settings.getBoolean(name, false); + } + + private void handleTaskOutcome(@NonNull Task<Void> task, CallbackContext callbackContext) { + try { + task.addOnCompleteListener(new OnCompleteListener<Void>() { + @Override + public void onComplete(@NonNull Task<Void> task) { + try { + if (task.isSuccessful() || task.getException() == null) { + callbackContext.success(); + }else if(task.getException() != null){ + callbackContext.error(task.getException().getMessage()); + }else{ + callbackContext.error("Task failed for unknown reason"); + } + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + }; + }); + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + + private void handleAuthTaskOutcome(@NonNull Task<AuthResult> task, CallbackContext callbackContext) { + try { + if (task.isSuccessful() || task.getException() == null) { + callbackContext.success(); + }else{ + String errMessage = task.getException().getMessage(); + if (task.getException() instanceof FirebaseAuthInvalidCredentialsException) { + errMessage = "Invalid verification code"; + } + callbackContext.error(errMessage); + } + } catch (Exception e) { + handleExceptionWithContext(e, callbackContext); + } + } + + private AuthCredential obtainAuthCredential(JSONObject jsonCredential) throws JSONException { + AuthCredential authCredential = null; + if(jsonCredential.has("verificationId") && jsonCredential.has("code")){ + Log.d(TAG, "Using specified verificationId and code to authenticate"); + authCredential = (AuthCredential) PhoneAuthProvider.getCredential(jsonCredential.getString("verificationId"), jsonCredential.getString("code")); + }else if(jsonCredential.has("id") && FirebasePlugin.instance.authCredentials.containsKey(jsonCredential.getString("id"))){ + Log.d(TAG, "Using native auth credential to authenticate"); + authCredential = FirebasePlugin.instance.authCredentials.get(jsonCredential.getString("id")); + } + return authCredential; + } + + private OAuthProvider obtainAuthProvider(JSONObject jsonCredential) throws JSONException{ + OAuthProvider authProvider = null; + if(jsonCredential.has("id") && FirebasePlugin.instance.authProviders.containsKey(jsonCredential.getString("id"))){ + Log.d(TAG, "Using native auth provider to authenticate"); + authProvider = FirebasePlugin.instance.authProviders.get(jsonCredential.getString("id")); + } + return authProvider; + } + + + private static class AuthResultOnSuccessListener implements OnSuccessListener<AuthResult> { + @Override + public void onSuccess(AuthResult authResult) { + Log.d(TAG, "AuthResult:onSuccess:" + authResult); + if(FirebasePlugin.instance.authResultCallbackContext != null){ + FirebasePlugin.instance.authResultCallbackContext.success(); + } + } + } + + private static class AuthResultOnFailureListener implements OnFailureListener { + @Override + public void onFailure(@NonNull Exception e) { + Log.w(TAG, "AuthResult:onFailure", e); + if(FirebasePlugin.instance.authResultCallbackContext != null){ + FirebasePlugin.instance.authResultCallbackContext.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, e.getMessage())); + } + } + } + + private static class AuthResultOnCompleteListener implements OnCompleteListener<AuthResult> { + private final CallbackContext callbackContext; + + public AuthResultOnCompleteListener(CallbackContext callbackContext) { + this.callbackContext = callbackContext; + } + + @Override + public void onComplete(@NonNull Task<AuthResult> task) { + FirebasePlugin.instance.handleAuthTaskOutcome(task, callbackContext); + } + } + + private static class AuthStateListener implements FirebaseAuth.AuthStateListener { + @Override + public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) { + try { + if(!FirebasePlugin.instance.authStateChangeListenerInitialized){ + FirebasePlugin.instance.authStateChangeListenerInitialized = true; + }else{ + FirebaseUser user = firebaseAuth.getCurrentUser(); + FirebasePlugin.instance.executeGlobalJavascript(JS_GLOBAL_NAMESPACE+"_onAuthStateChange("+(user != null ? "true" : "false")+")"); + } + } catch (Exception e) { + handleExceptionWithoutContext(e); + } + } + } + + private Map<String, Object> jsonStringToMap(String jsonString) throws JSONException { + Type type = new TypeToken<Map<String, Object>>(){}.getType(); + return gson.fromJson(jsonString, type); + } + + + private JSONObject mapToJsonObject(Map<String, Object> map) throws JSONException { + String jsonString = gson.toJson(map); + return new JSONObject(jsonString); + } + + private void logMessageToCrashlytics(String message){ + if(isCrashlyticsEnabled()){ + try{ + firebaseCrashlytics.log(message); + }catch (Exception e){ + Log.e(TAG, e.getMessage()); + } + }else{ + Log.e(TAG, "Cannot log message - Crashlytics collection is disabled"); + } + } + + private void logExceptionToCrashlytics(Exception exception){ + if(isCrashlyticsEnabled()){ + try{ + firebaseCrashlytics.recordException(exception); + }catch (Exception e){ + Log.e(TAG, e.getMessage()); + } + }else{ + Log.e(TAG, "Cannot log exception - Crashlytics collection is disabled"); + } + } +} |
