summaryrefslogtreecommitdiff
path: root/StoneIsland/plugins/cordova-plugin-firebasex/src/android
diff options
context:
space:
mode:
Diffstat (limited to 'StoneIsland/plugins/cordova-plugin-firebasex/src/android')
-rw-r--r--StoneIsland/plugins/cordova-plugin-firebasex/src/android/FirebasePlugin.java2441
-rw-r--r--StoneIsland/plugins/cordova-plugin-firebasex/src/android/FirebasePluginMessageReceiver.java28
-rw-r--r--StoneIsland/plugins/cordova-plugin-firebasex/src/android/FirebasePluginMessageReceiverManager.java41
-rw-r--r--StoneIsland/plugins/cordova-plugin-firebasex/src/android/FirebasePluginMessagingService.java348
-rw-r--r--StoneIsland/plugins/cordova-plugin-firebasex/src/android/JavaScriptException.java45
-rw-r--r--StoneIsland/plugins/cordova-plugin-firebasex/src/android/OnNotificationOpenReceiver.java36
-rw-r--r--StoneIsland/plugins/cordova-plugin-firebasex/src/android/build.gradle48
-rw-r--r--StoneIsland/plugins/cordova-plugin-firebasex/src/android/colors.xml3
-rw-r--r--StoneIsland/plugins/cordova-plugin-firebasex/src/android/cordova-plugin-firebase-strings.xml5
9 files changed, 2995 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");
+ }
+ }
+}
diff --git a/StoneIsland/plugins/cordova-plugin-firebasex/src/android/FirebasePluginMessageReceiver.java b/StoneIsland/plugins/cordova-plugin-firebasex/src/android/FirebasePluginMessageReceiver.java
new file mode 100644
index 00000000..1bb76d08
--- /dev/null
+++ b/StoneIsland/plugins/cordova-plugin-firebasex/src/android/FirebasePluginMessageReceiver.java
@@ -0,0 +1,28 @@
+package org.apache.cordova.firebase;
+
+import android.os.Bundle;
+
+import com.google.firebase.messaging.RemoteMessage;
+
+public abstract class FirebasePluginMessageReceiver {
+
+ public FirebasePluginMessageReceiver() {
+ FirebasePluginMessageReceiverManager.register(this);
+ }
+
+ /**
+ * Concrete subclasses should override this and return true if they handle the received message.
+ *
+ * @param remoteMessage
+ * @return true if the received message was handled by the receiver so should not be handled by FirebasePluginMessagingService.onMessageReceived()
+ */
+ public abstract boolean onMessageReceived(RemoteMessage remoteMessage);
+
+ /**
+ * Concrete subclasses should override this and return true if they handle the message bundle before it's sent to FirebasePlugin.sendMessage().
+ *
+ * @param bundle
+ * @return true if the received bundle was handled by the receiver so should not be handled by FirebasePlugin.
+ */
+ public abstract boolean sendMessage(Bundle bundle);
+}
diff --git a/StoneIsland/plugins/cordova-plugin-firebasex/src/android/FirebasePluginMessageReceiverManager.java b/StoneIsland/plugins/cordova-plugin-firebasex/src/android/FirebasePluginMessageReceiverManager.java
new file mode 100644
index 00000000..299e5cda
--- /dev/null
+++ b/StoneIsland/plugins/cordova-plugin-firebasex/src/android/FirebasePluginMessageReceiverManager.java
@@ -0,0 +1,41 @@
+package org.apache.cordova.firebase;
+
+import android.os.Bundle;
+
+import com.google.firebase.messaging.RemoteMessage;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class FirebasePluginMessageReceiverManager {
+
+ private static List<FirebasePluginMessageReceiver> receivers = new ArrayList<FirebasePluginMessageReceiver>();
+
+ public static void register(FirebasePluginMessageReceiver receiver) {
+ receivers.add(receiver);
+ }
+
+ public static boolean onMessageReceived(RemoteMessage remoteMessage) {
+ boolean handled = false;
+ for (FirebasePluginMessageReceiver receiver : receivers) {
+ boolean wasHandled = receiver.onMessageReceived(remoteMessage);
+ if (wasHandled) {
+ handled = true;
+ }
+ }
+
+ return handled;
+ }
+
+ public static boolean sendMessage(Bundle bundle) {
+ boolean handled = false;
+ for (FirebasePluginMessageReceiver receiver : receivers) {
+ boolean wasHandled = receiver.sendMessage(bundle);
+ if (wasHandled) {
+ handled = true;
+ }
+ }
+
+ return handled;
+ }
+}
diff --git a/StoneIsland/plugins/cordova-plugin-firebasex/src/android/FirebasePluginMessagingService.java b/StoneIsland/plugins/cordova-plugin-firebasex/src/android/FirebasePluginMessagingService.java
new file mode 100644
index 00000000..92e6aafb
--- /dev/null
+++ b/StoneIsland/plugins/cordova-plugin-firebasex/src/android/FirebasePluginMessagingService.java
@@ -0,0 +1,348 @@
+package org.apache.cordova.firebase;
+
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.BitmapFactory;
+import android.media.RingtoneManager;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import androidx.core.app.NotificationCompat;
+import android.util.Log;
+import android.app.Notification;
+import android.text.TextUtils;
+import android.content.ContentResolver;
+import android.graphics.Color;
+
+import com.google.firebase.crashlytics.FirebaseCrashlytics;
+import com.google.firebase.messaging.FirebaseMessagingService;
+import com.google.firebase.messaging.RemoteMessage;
+
+import java.util.Map;
+import java.util.Random;
+
+public class FirebasePluginMessagingService extends FirebaseMessagingService {
+
+ private static final String TAG = "FirebasePlugin";
+
+ static final String defaultSmallIconName = "notification_icon";
+ static final String defaultLargeIconName = "notification_icon_large";
+
+
+ /**
+ * Called if InstanceID token is updated. This may occur if the security of
+ * the previous token had been compromised. Note that this is called when the InstanceID token
+ * is initially generated so this is where you would retrieve the token.
+ */
+ @Override
+ public void onNewToken(String refreshedToken) {
+ try{
+ super.onNewToken(refreshedToken);
+ Log.d(TAG, "Refreshed token: " + refreshedToken);
+ FirebasePlugin.sendToken(refreshedToken);
+ }catch (Exception e){
+ FirebasePlugin.handleExceptionWithoutContext(e);
+ }
+ }
+
+
+ /**
+ * Called when message is received.
+ * Called IF message is a data message (i.e. NOT sent from Firebase console)
+ * OR if message is a notification message (e.g. sent from Firebase console) AND app is in foreground.
+ * Notification messages received while app is in background will not be processed by this method;
+ * they are handled internally by the OS.
+ *
+ * @param remoteMessage Object representing the message received from Firebase Cloud Messaging.
+ */
+ @Override
+ public void onMessageReceived(RemoteMessage remoteMessage) {
+ try{
+ // [START_EXCLUDE]
+ // There are two types of messages data messages and notification messages. Data messages are handled
+ // here in onMessageReceived whether the app is in the foreground or background. Data messages are the type
+ // traditionally used with GCM. Notification messages are only received here in onMessageReceived when the app
+ // is in the foreground. When the app is in the background an automatically generated notification is displayed.
+ // When the user taps on the notification they are returned to the app. Messages containing both notification
+ // and data payloads are treated as notification messages. The Firebase console always sends notification
+ // messages. For more see: https://firebase.google.com/docs/cloud-messaging/concept-options
+ // [END_EXCLUDE]
+
+ // Pass the message to the receiver manager so any registered receivers can decide to handle it
+ boolean wasHandled = FirebasePluginMessageReceiverManager.onMessageReceived(remoteMessage);
+ if (wasHandled) {
+ Log.d(TAG, "Message was handled by a registered receiver");
+
+ // Don't process the message in this method.
+ return;
+ }
+
+ if(FirebasePlugin.applicationContext == null){
+ FirebasePlugin.applicationContext = this.getApplicationContext();
+ }
+
+ // TODO(developer): Handle FCM messages here.
+ // Not getting messages here? See why this may be: https://goo.gl/39bRNJ
+ String messageType;
+ String title = null;
+ String body = null;
+ String id = null;
+ String sound = null;
+ String vibrate = null;
+ String light = null;
+ String color = null;
+ String icon = null;
+ String channelId = null;
+ String visibility = null;
+ String priority = null;
+ boolean foregroundNotification = false;
+
+ Map<String, String> data = remoteMessage.getData();
+
+ if (remoteMessage.getNotification() != null) {
+ // Notification message payload
+ Log.i(TAG, "Received message: notification");
+ messageType = "notification";
+ id = remoteMessage.getMessageId();
+ RemoteMessage.Notification notification = remoteMessage.getNotification();
+ title = notification.getTitle();
+ body = notification.getBody();
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ channelId = notification.getChannelId();
+ }
+ sound = notification.getSound();
+ color = notification.getColor();
+ icon = notification.getIcon();
+ }else{
+ Log.i(TAG, "Received message: data");
+ messageType = "data";
+ }
+
+ if (data != null) {
+ // Data message payload
+ if(data.containsKey("notification_foreground")){
+ foregroundNotification = true;
+ }
+ if(data.containsKey("notification_title")) title = data.get("notification_title");
+ if(data.containsKey("notification_body")) body = data.get("notification_body");
+ if(data.containsKey("notification_android_channel_id")) channelId = data.get("notification_android_channel_id");
+ if(data.containsKey("notification_android_id")) id = data.get("notification_android_id");
+ if(data.containsKey("notification_android_sound")) sound = data.get("notification_android_sound");
+ if(data.containsKey("notification_android_vibrate")) vibrate = data.get("notification_android_vibrate");
+ if(data.containsKey("notification_android_light")) light = data.get("notification_android_light"); //String containing hex ARGB color, miliseconds on, miliseconds off, example: '#FFFF00FF,1000,3000'
+ if(data.containsKey("notification_android_color")) color = data.get("notification_android_color");
+ if(data.containsKey("notification_android_icon")) icon = data.get("notification_android_icon");
+ if(data.containsKey("notification_android_visibility")) visibility = data.get("notification_android_visibility");
+ if(data.containsKey("notification_android_priority")) priority = data.get("notification_android_priority");
+ }
+
+ if (TextUtils.isEmpty(id)) {
+ Random rand = new Random();
+ int n = rand.nextInt(50) + 1;
+ id = Integer.toString(n);
+ }
+
+ Log.d(TAG, "From: " + remoteMessage.getFrom());
+ Log.d(TAG, "Id: " + id);
+ Log.d(TAG, "Title: " + title);
+ Log.d(TAG, "Body: " + body);
+ Log.d(TAG, "Sound: " + sound);
+ Log.d(TAG, "Vibrate: " + vibrate);
+ Log.d(TAG, "Light: " + light);
+ Log.d(TAG, "Color: " + color);
+ Log.d(TAG, "Icon: " + icon);
+ Log.d(TAG, "Channel Id: " + channelId);
+ Log.d(TAG, "Visibility: " + visibility);
+ Log.d(TAG, "Priority: " + priority);
+
+
+ if (!TextUtils.isEmpty(body) || !TextUtils.isEmpty(title) || (data != null && !data.isEmpty())) {
+ boolean showNotification = (FirebasePlugin.inBackground() || !FirebasePlugin.hasNotificationsCallback() || foregroundNotification) && (!TextUtils.isEmpty(body) || !TextUtils.isEmpty(title));
+ sendMessage(remoteMessage, data, messageType, id, title, body, showNotification, sound, vibrate, light, color, icon, channelId, priority, visibility);
+ }
+ }catch (Exception e){
+ FirebasePlugin.handleExceptionWithoutContext(e);
+ }
+ }
+
+ private void sendMessage(RemoteMessage remoteMessage, Map<String, String> data, String messageType, String id, String title, String body, boolean showNotification, String sound, String vibrate, String light, String color, String icon, String channelId, String priority, String visibility) {
+ Log.d(TAG, "sendMessage(): messageType="+messageType+"; showNotification="+showNotification+"; id="+id+"; title="+title+"; body="+body+"; sound="+sound+"; vibrate="+vibrate+"; light="+light+"; color="+color+"; icon="+icon+"; channel="+channelId+"; data="+data.toString());
+ Bundle bundle = new Bundle();
+ for (String key : data.keySet()) {
+ bundle.putString(key, data.get(key));
+ }
+ bundle.putString("messageType", messageType);
+ this.putKVInBundle("id", id, bundle);
+ this.putKVInBundle("title", title, bundle);
+ this.putKVInBundle("body", body, bundle);
+ this.putKVInBundle("sound", sound, bundle);
+ this.putKVInBundle("vibrate", vibrate, bundle);
+ this.putKVInBundle("light", light, bundle);
+ this.putKVInBundle("color", color, bundle);
+ this.putKVInBundle("icon", icon, bundle);
+ this.putKVInBundle("channel_id", channelId, bundle);
+ this.putKVInBundle("priority", priority, bundle);
+ this.putKVInBundle("visibility", visibility, bundle);
+ this.putKVInBundle("show_notification", String.valueOf(showNotification), bundle);
+ this.putKVInBundle("from", remoteMessage.getFrom(), bundle);
+ this.putKVInBundle("collapse_key", remoteMessage.getCollapseKey(), bundle);
+ this.putKVInBundle("sent_time", String.valueOf(remoteMessage.getSentTime()), bundle);
+ this.putKVInBundle("ttl", String.valueOf(remoteMessage.getTtl()), bundle);
+
+ if (showNotification) {
+ Intent intent = new Intent(this, OnNotificationOpenReceiver.class);
+ intent.putExtras(bundle);
+ PendingIntent pendingIntent = PendingIntent.getBroadcast(this, id.hashCode(), intent, PendingIntent.FLAG_UPDATE_CURRENT);
+
+ // Channel
+ if(channelId == null || !FirebasePlugin.channelExists(channelId)){
+ channelId = FirebasePlugin.defaultChannelId;
+ }
+ if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
+ Log.d(TAG, "Channel ID: "+channelId);
+ }
+
+ NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, channelId);
+ notificationBuilder
+ .setContentTitle(title)
+ .setContentText(body)
+ .setStyle(new NotificationCompat.BigTextStyle().bigText(body))
+ .setAutoCancel(true)
+ .setContentIntent(pendingIntent);
+
+ // On Android O+ the sound/lights/vibration are determined by the channel ID
+ if(Build.VERSION.SDK_INT < Build.VERSION_CODES.O){
+ // Sound
+ if (sound == null) {
+ Log.d(TAG, "Sound: none");
+ }else if (sound.equals("default")) {
+ notificationBuilder.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION));
+ Log.d(TAG, "Sound: default");
+ }else{
+ Uri soundPath = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + getPackageName() + "/raw/" + sound);
+ Log.d(TAG, "Sound: custom=" + sound+"; path="+soundPath.toString());
+ notificationBuilder.setSound(soundPath);
+ }
+
+ // Light
+ if (light != null) {
+ try {
+ String[] lightsComponents = color.replaceAll("\\s", "").split(",");
+ if (lightsComponents.length == 3) {
+ int lightArgb = Color.parseColor(lightsComponents[0]);
+ int lightOnMs = Integer.parseInt(lightsComponents[1]);
+ int lightOffMs = Integer.parseInt(lightsComponents[2]);
+ notificationBuilder.setLights(lightArgb, lightOnMs, lightOffMs);
+ Log.d(TAG, "Lights: color="+lightsComponents[0]+"; on(ms)="+lightsComponents[2]+"; off(ms)="+lightsComponents[3]);
+ }
+
+ } catch (Exception e) {}
+ }
+
+ // Vibrate
+ if (vibrate != null){
+ try {
+ String[] sVibrations = vibrate.replaceAll("\\s", "").split(",");
+ long[] lVibrations = new long[sVibrations.length];
+ int i=0;
+ for(String sVibration: sVibrations){
+ lVibrations[i] = Integer.parseInt(sVibration.trim());
+ i++;
+ }
+ notificationBuilder.setVibrate(lVibrations);
+ Log.d(TAG, "Vibrate: "+vibrate);
+ } catch (Exception e) {
+ Log.e(TAG, e.getMessage());
+ }
+ }
+ }
+
+
+ // Icon
+ int defaultSmallIconResID = getResources().getIdentifier(defaultSmallIconName, "drawable", getPackageName());
+ int customSmallIconResID = 0;
+ if(icon != null){
+ customSmallIconResID = getResources().getIdentifier(icon, "drawable", getPackageName());
+ }
+
+ if (customSmallIconResID != 0) {
+ notificationBuilder.setSmallIcon(customSmallIconResID);
+ Log.d(TAG, "Small icon: custom="+icon);
+ }else if (defaultSmallIconResID != 0) {
+ Log.d(TAG, "Small icon: default="+defaultSmallIconName);
+ notificationBuilder.setSmallIcon(defaultSmallIconResID);
+ } else {
+ Log.d(TAG, "Small icon: application");
+ notificationBuilder.setSmallIcon(getApplicationInfo().icon);
+ }
+
+ if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
+ int defaultLargeIconResID = getResources().getIdentifier(defaultLargeIconName, "drawable", getPackageName());
+ int customLargeIconResID = 0;
+ if(icon != null){
+ customLargeIconResID = getResources().getIdentifier(icon+"_large", "drawable", getPackageName());
+ }
+
+ int largeIconResID;
+ if (customLargeIconResID != 0 || defaultLargeIconResID != 0) {
+ if (customLargeIconResID != 0) {
+ largeIconResID = customLargeIconResID;
+ Log.d(TAG, "Large icon: custom="+icon);
+ }else{
+ Log.d(TAG, "Large icon: default="+defaultLargeIconName);
+ largeIconResID = defaultLargeIconResID;
+ }
+ notificationBuilder.setLargeIcon(BitmapFactory.decodeResource(getApplicationContext().getResources(), largeIconResID));
+ }
+ }
+
+ // Color
+ if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
+ int defaultColor = getResources().getColor(getResources().getIdentifier("accent", "color", getPackageName()), null);
+ if(color != null){
+ notificationBuilder.setColor(Color.parseColor(color));
+ Log.d(TAG, "Color: custom="+color);
+ }else{
+ Log.d(TAG, "Color: default");
+ notificationBuilder.setColor(defaultColor);
+ }
+ }
+
+ // Visibility
+ int iVisibility = NotificationCompat.VISIBILITY_PUBLIC;
+ if(visibility != null){
+ iVisibility = Integer.parseInt(visibility);
+ }
+ Log.d(TAG, "Visibility: " + iVisibility);
+ notificationBuilder.setVisibility(iVisibility);
+
+ // Priority
+ int iPriority = NotificationCompat.PRIORITY_MAX;
+ if(priority != null){
+ iPriority = Integer.parseInt(priority);
+ }
+ Log.d(TAG, "Priority: " + iPriority);
+ notificationBuilder.setPriority(iPriority);
+
+
+ // Build notification
+ Notification notification = notificationBuilder.build();
+
+ // Display notification
+ NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
+ Log.d(TAG, "show notification: "+notification.toString());
+ notificationManager.notify(id.hashCode(), notification);
+ }
+ // Send to plugin
+ FirebasePlugin.sendMessage(bundle, this.getApplicationContext());
+ }
+
+ private void putKVInBundle(String k, String v, Bundle b){
+ if(v != null && !b.containsKey(k)){
+ b.putString(k, v);
+ }
+ }
+}
diff --git a/StoneIsland/plugins/cordova-plugin-firebasex/src/android/JavaScriptException.java b/StoneIsland/plugins/cordova-plugin-firebasex/src/android/JavaScriptException.java
new file mode 100644
index 00000000..3d423fa3
--- /dev/null
+++ b/StoneIsland/plugins/cordova-plugin-firebasex/src/android/JavaScriptException.java
@@ -0,0 +1,45 @@
+package org.apache.cordova.firebase;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+/**
+ * Exception class to log Javascript based exceptions with stacktrace.
+ *
+ * Picked from https://github.com/wizpanda/cordova-plugin-firebase-lib/pull/8/files
+ *
+ * @author https://github.com/sagrawal31/
+ */
+public class JavaScriptException extends Exception {
+
+ public JavaScriptException(String message) {
+ super(message);
+ }
+
+ public JavaScriptException(String message, JSONArray stackTrace) throws JSONException {
+ super(message);
+ this.handleStacktrace(stackTrace);
+ }
+
+ private void handleStacktrace(JSONArray stackTrace) throws JSONException {
+ if (stackTrace == null) {
+ return;
+ }
+
+ StackTraceElement[] trace = new StackTraceElement[stackTrace.length()];
+
+ for (int i = 0; i < stackTrace.length(); i++) {
+ JSONObject elem = stackTrace.getJSONObject(i);
+
+ trace[i] = new StackTraceElement(
+ "undefined",
+ elem.optString("functionName", "undefined"),
+ elem.optString("fileName", "undefined"),
+ elem.optInt("lineNumber", -1)
+ );
+ }
+
+ this.setStackTrace(trace);
+ }
+}
diff --git a/StoneIsland/plugins/cordova-plugin-firebasex/src/android/OnNotificationOpenReceiver.java b/StoneIsland/plugins/cordova-plugin-firebasex/src/android/OnNotificationOpenReceiver.java
new file mode 100644
index 00000000..818382ef
--- /dev/null
+++ b/StoneIsland/plugins/cordova-plugin-firebasex/src/android/OnNotificationOpenReceiver.java
@@ -0,0 +1,36 @@
+package org.apache.cordova.firebase;
+
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.util.Log;
+
+public class OnNotificationOpenReceiver extends BroadcastReceiver {
+
+ // Called on tapping foreground notification
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ try{
+ PackageManager pm = context.getPackageManager();
+
+ Intent launchIntent = pm.getLaunchIntentForPackage(context.getPackageName());
+ launchIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
+
+ Bundle data = intent.getExtras();
+ if(!data.containsKey("messageType")) data.putString("messageType", "notification");
+ data.putString("tap", FirebasePlugin.inBackground() ? "background" : "foreground");
+
+ Log.d(FirebasePlugin.TAG, "OnNotificationOpenReceiver.onReceive(): "+data.toString());
+
+ FirebasePlugin.sendMessage(data, context);
+
+ launchIntent.putExtras(data);
+ context.startActivity(launchIntent);
+ }catch (Exception e){
+ FirebasePlugin.handleExceptionWithoutContext(e);
+ }
+ }
+}
diff --git a/StoneIsland/plugins/cordova-plugin-firebasex/src/android/build.gradle b/StoneIsland/plugins/cordova-plugin-firebasex/src/android/build.gradle
new file mode 100644
index 00000000..89c743f1
--- /dev/null
+++ b/StoneIsland/plugins/cordova-plugin-firebasex/src/android/build.gradle
@@ -0,0 +1,48 @@
+buildscript {
+ repositories {
+ google()
+ mavenCentral()
+ jcenter()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:3.4.1'
+ classpath 'com.google.gms:google-services:4.3.3'
+ classpath 'com.google.firebase:firebase-crashlytics-gradle:2.1.1'
+ }
+}
+repositories {
+ mavenCentral()
+ maven {
+ url "https://maven.google.com"
+ }
+}
+
+apply plugin: com.google.firebase.crashlytics.buildtools.gradle.CrashlyticsPlugin
+android {
+ buildTypes {
+ debug {
+ firebaseCrashlytics {
+ mappingFileUploadEnabled false
+ }
+ }
+ release {
+ firebaseCrashlytics {
+ nativeSymbolUploadEnabled true
+ unstrippedNativeLibsDir "obj/local"
+ strippedNativeLibsDir "build/intermediates/jniLibs/release"
+ }
+ }
+ }
+}
+
+cdvPluginPostBuildExtras.add({
+ rootProject.subprojects {
+ if (name == "app") {
+ if (!plugins.hasPlugin('com.google.gms.google-services')) {
+ apply plugin: com.google.gms.googleservices.GoogleServicesPlugin
+ }
+ }
+ }
+})
+
+
diff --git a/StoneIsland/plugins/cordova-plugin-firebasex/src/android/colors.xml b/StoneIsland/plugins/cordova-plugin-firebasex/src/android/colors.xml
new file mode 100644
index 00000000..045e125f
--- /dev/null
+++ b/StoneIsland/plugins/cordova-plugin-firebasex/src/android/colors.xml
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+</resources>
diff --git a/StoneIsland/plugins/cordova-plugin-firebasex/src/android/cordova-plugin-firebase-strings.xml b/StoneIsland/plugins/cordova-plugin-firebasex/src/android/cordova-plugin-firebase-strings.xml
new file mode 100644
index 00000000..1f1d32cc
--- /dev/null
+++ b/StoneIsland/plugins/cordova-plugin-firebasex/src/android/cordova-plugin-firebase-strings.xml
@@ -0,0 +1,5 @@
+<?xml version='1.0' encoding='utf-8'?>
+<resources>
+ <string name="default_notification_channel_id">fcm_default_channel</string>
+ <string name="default_notification_channel_name">Default</string>
+</resources> \ No newline at end of file