diff --git a/app/AndroidManifest.xml b/app/AndroidManifest.xml
index d401edc866..c0e344c920 100644
--- a/app/AndroidManifest.xml
+++ b/app/AndroidManifest.xml
@@ -229,6 +229,12 @@
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths" />
+
diff --git a/app/build.gradle b/app/build.gradle
index f32e379890..57f3f5cf76 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -194,6 +194,7 @@ ext {
'ycVSQSeO2glc6XZZ+CJudAPXe8iFWLQp3kBBnBmVcBXCOQFO7aLgQMv4nqKZsLW0' +
'HaAJkjpnc165Os+aYwIDAQAB')
GOOGLE_SERVICES_API_KEY = loadProp('GOOGLE_SERVICES_API_KEY', '')
+ FIREBASE_ENABLED = !GOOGLE_SERVICES_API_KEY.toString().isEmpty()
GOOGLE_CLOUD_PROJECT_NUMBER = loadProp('GOOGLE_CLOUD_PROJECT_NUMBER', -1L)
QA_BETA_APP_ID = ''
STANDALONE_APP_ID = ''
@@ -315,6 +316,8 @@ android {
buildConfigField 'String', 'FIREBASE_DATABASE_URL', "\"${project.ext.FIREBASE_DATABASE_URL}\""
buildConfigField 'String', 'CCC_HOST', "\"connect.dimagi.com\""
buildConfigField 'long', 'GOOGLE_CLOUD_PROJECT_NUMBER', "${project.ext.GOOGLE_CLOUD_PROJECT_NUMBER}"
+ buildConfigField 'boolean', 'FIREBASE_ENABLED', "${project.ext.FIREBASE_ENABLED}"
+ manifestPlaceholders["firebaseInitEnabled"] = project.ext.FIREBASE_ENABLED
testInstrumentationRunner 'org.commcare.CommCareJUnitRunner'
}
diff --git a/app/src/org/commcare/CommCareApplication.java b/app/src/org/commcare/CommCareApplication.java
index 18d598f819..f67a3f1ee2 100644
--- a/app/src/org/commcare/CommCareApplication.java
+++ b/app/src/org/commcare/CommCareApplication.java
@@ -119,6 +119,7 @@
import org.commcare.utils.DeviceIdentifier;
import org.commcare.utils.FileUtil;
import org.commcare.utils.FirebaseMessagingUtil;
+import org.commcare.utils.FirebaseUtils;
import org.commcare.utils.GlobalConstants;
import org.commcare.utils.MarkupUtil;
import org.commcare.utils.MultipleAppsUtil;
@@ -222,9 +223,10 @@ public void onCreate() {
turnOnStrictMode();
CommCareApplication.app = this;
+
CrashUtil.init();
DataChangeLogger.init(this);
- if (!BuildConfig.DEBUG) {
+ if (FirebaseUtils.isFirebaseEnabled()) {
FirebasePerformance.getInstance().setPerformanceCollectionEnabled(true);
}
@@ -440,6 +442,9 @@ public SecretKey createNewSymmetricKey() {
}
synchronized public FirebaseAnalytics getAnalyticsInstance() {
+ if (!FirebaseUtils.isFirebaseEnabled()) {
+ return null;
+ }
if (analyticsInstance == null) {
analyticsInstance = FirebaseAnalytics.getInstance(this);
}
diff --git a/app/src/org/commcare/fragments/personalId/PersonalIdPhoneVerificationFragment.java b/app/src/org/commcare/fragments/personalId/PersonalIdPhoneVerificationFragment.java
index 4e48993d37..9d9f580b2c 100644
--- a/app/src/org/commcare/fragments/personalId/PersonalIdPhoneVerificationFragment.java
+++ b/app/src/org/commcare/fragments/personalId/PersonalIdPhoneVerificationFragment.java
@@ -32,6 +32,7 @@
import org.commcare.dalvik.databinding.ScreenPersonalidPhoneVerifyBinding;
import org.commcare.google.services.analytics.FirebaseAnalyticsUtil;
import org.commcare.util.LogTypes;
+import org.commcare.utils.FirebaseUtils;
import org.commcare.utils.KeyboardHelper;
import org.commcare.utils.OtpErrorType;
import org.commcare.utils.OtpManager;
@@ -151,8 +152,10 @@ public void onPersonalIdApiFailure(
}
};
+ // Use fallback option when Firebase is not configured.
// The last OTP method may be Twilio (via PersonalID) after restoring this fragment.
- Boolean useOtpFallback = SMS_METHOD_PERSONAL_ID.equalsIgnoreCase(lastOtpMethod);
+ Boolean useOtpFallback = SMS_METHOD_PERSONAL_ID.equalsIgnoreCase(lastOtpMethod) ||
+ !FirebaseUtils.isFirebaseEnabled();
setupOtpManager(useOtpFallback);
}
diff --git a/app/src/org/commcare/google/services/analytics/CCPerfMonitoring.kt b/app/src/org/commcare/google/services/analytics/CCPerfMonitoring.kt
index 1af71aa0e3..7b3e80fa21 100644
--- a/app/src/org/commcare/google/services/analytics/CCPerfMonitoring.kt
+++ b/app/src/org/commcare/google/services/analytics/CCPerfMonitoring.kt
@@ -4,6 +4,7 @@ import com.google.firebase.perf.FirebasePerformance
import com.google.firebase.perf.metrics.Trace
import org.apache.commons.io.FilenameUtils
import org.commcare.android.logging.ReportingUtils
+import org.commcare.utils.FirebaseUtils
import org.javarosa.core.services.Logger
object CCPerfMonitoring {
@@ -34,6 +35,9 @@ object CCPerfMonitoring {
fun startTracing(traceName: String): Trace? {
+ if (!FirebaseUtils.isFirebaseEnabled) {
+ return null
+ }
try {
val trace = FirebasePerformance.getInstance().newTrace(traceName)
trace.putAttribute(CCAnalyticsParam.CCHQ_DOMAIN, ReportingUtils.getDomain())
diff --git a/app/src/org/commcare/google/services/analytics/FirebaseAnalyticsUtil.java b/app/src/org/commcare/google/services/analytics/FirebaseAnalyticsUtil.java
index f59e2b1ab4..33a544855e 100644
--- a/app/src/org/commcare/google/services/analytics/FirebaseAnalyticsUtil.java
+++ b/app/src/org/commcare/google/services/analytics/FirebaseAnalyticsUtil.java
@@ -21,6 +21,7 @@
import org.commcare.preferences.MainConfigurablePreferences;
import org.commcare.suite.model.OfflineUserRestore;
import org.commcare.util.EncryptionUtils;
+import org.commcare.utils.FirebaseUtils;
import org.commcare.utils.FormUploadResult;
import org.javarosa.core.services.Logger;
@@ -78,11 +79,14 @@ private static void reportEvent(String eventName, String[] paramKeys, String[] p
}
private static void reportEvent(String eventName, Bundle params) {
- if (analyticsDisabled()) {
+ if (!FirebaseUtils.isAnalyticsEnabled()) {
return;
}
FirebaseAnalytics analyticsInstance = CommCareApplication.instance().getAnalyticsInstance();
+ if (analyticsInstance == null) {
+ return;
+ }
setUserProperties(analyticsInstance);
analyticsInstance.logEvent(eventName, params);
}
@@ -357,14 +361,14 @@ public static void reportInAppUpdateResult(boolean result, String failureReason)
}
public static void reportFeatureUsage(String feature) {
- if (analyticsDisabled()) {
+ if (!FirebaseUtils.isAnalyticsEnabled()) {
return;
}
reportEvent(CCAnalyticsEvent.FEATURE_USAGE, FirebaseAnalytics.Param.ITEM_CATEGORY, feature);
}
private static void reportFeatureUsage(String feature, String mode) {
- if (analyticsDisabled()) {
+ if (!FirebaseUtils.isAnalyticsEnabled()) {
return;
}
@@ -410,10 +414,6 @@ public static void reportTimedSession(
}
}
- private static boolean analyticsDisabled() {
- return !MainConfigurablePreferences.isAnalyticsEnabled();
- }
-
private static boolean rateLimitReporting(double percentOfEventsToReport) {
return Math.random() < percentOfEventsToReport;
}
@@ -767,6 +767,9 @@ public static void flagPersonalIDDemoUser(Boolean isPersonalIDDemoUser) {
}
FirebaseAnalytics analyticsInstance = CommCareApplication.instance().getAnalyticsInstance();
+ if (analyticsInstance == null) {
+ return;
+ }
analyticsInstance.setUserProperty(
CCAnalyticsParam.IS_PERSONAL_ID_DEMO_USER,
String.valueOf(isPersonalIDDemoUser)
diff --git a/app/src/org/commcare/utils/CrashUtil.java b/app/src/org/commcare/utils/CrashUtil.java
index 2b6eee6ee3..110e29d4bd 100644
--- a/app/src/org/commcare/utils/CrashUtil.java
+++ b/app/src/org/commcare/utils/CrashUtil.java
@@ -1,7 +1,6 @@
package org.commcare.utils;
import org.commcare.android.logging.ReportingUtils;
-import org.commcare.dalvik.BuildConfig;
import com.google.firebase.crashlytics.FirebaseCrashlytics;
@@ -17,7 +16,7 @@ public class CrashUtil {
private static final String DOMAIN = "domain";
private static final String DEVICE_ID = "device_id";
- private static boolean crashlyticsEnabled = BuildConfig.USE_CRASHLYTICS;
+ private static boolean crashlyticsEnabled = FirebaseUtils.isCrashlyticsEnabled();
public static void reportException(Throwable e) {
if (crashlyticsEnabled) {
diff --git a/app/src/org/commcare/utils/FirebaseMessagingUtil.java b/app/src/org/commcare/utils/FirebaseMessagingUtil.java
index 02ac0763f6..c3815e60d4 100644
--- a/app/src/org/commcare/utils/FirebaseMessagingUtil.java
+++ b/app/src/org/commcare/utils/FirebaseMessagingUtil.java
@@ -42,6 +42,7 @@
import org.commcare.services.FCMMessageData;
import org.commcare.sync.FirebaseMessagingDataSyncer;
import org.commcare.util.LogTypes;
+import org.commcare.utils.FirebaseUtils;
import org.javarosa.core.services.Logger;
import java.util.HashMap;
@@ -96,12 +97,16 @@ public static void updateFCMToken(String newToken) {
sharedPreferences.edit().putLong(FCM_TOKEN_TIME, System.currentTimeMillis()).apply();
}
+ /**
+ * This verification only runs if Firebase is available and configured
+ */
public static void verifyToken() {
- // TODO: Enable FCM in debug mode
- if (!BuildConfig.DEBUG) {
- // Retrieve the current Firebase Cloud Messaging (FCM) registration token
- FirebaseMessaging.getInstance().getToken().addOnCompleteListener(handleFCMTokenRetrieval());
+ if (!FirebaseUtils.isFirebaseEnabled()) {
+ return;
}
+
+ // Retrieve the current Firebase Cloud Messaging (FCM) registration token
+ FirebaseMessaging.getInstance().getToken().addOnCompleteListener(handleFCMTokenRetrieval());
}
private static OnCompleteListener handleFCMTokenRetrieval() {
diff --git a/app/src/org/commcare/utils/FirebaseUtils.kt b/app/src/org/commcare/utils/FirebaseUtils.kt
new file mode 100644
index 0000000000..0a317603d3
--- /dev/null
+++ b/app/src/org/commcare/utils/FirebaseUtils.kt
@@ -0,0 +1,22 @@
+package org.commcare.utils
+
+import org.commcare.dalvik.BuildConfig
+import org.commcare.preferences.MainConfigurablePreferences
+
+object FirebaseUtils {
+ @JvmStatic
+ val isFirebaseEnabled: Boolean
+ /**
+ * Returns whether Firebase services are available and configured. Firebase is disabled in debug mode
+ * When false, all Firebase API calls must be skipped.
+ */
+ get() = !BuildConfig.DEBUG && BuildConfig.FIREBASE_ENABLED
+
+ @JvmStatic
+ val isCrashlyticsEnabled: Boolean
+ get() = isFirebaseEnabled && BuildConfig.USE_CRASHLYTICS
+
+ @JvmStatic
+ val isAnalyticsEnabled: Boolean
+ get() = isFirebaseEnabled && MainConfigurablePreferences.isAnalyticsEnabled()
+}
diff --git a/app/unit-tests/src/org/commcare/android/tests/firebase/FirebaseUtilsTest.java b/app/unit-tests/src/org/commcare/android/tests/firebase/FirebaseUtilsTest.java
new file mode 100644
index 0000000000..11d8922456
--- /dev/null
+++ b/app/unit-tests/src/org/commcare/android/tests/firebase/FirebaseUtilsTest.java
@@ -0,0 +1,21 @@
+package org.commcare.android.tests.firebase;
+
+import static org.junit.Assert.assertEquals;
+
+import org.commcare.dalvik.BuildConfig;
+import org.commcare.utils.FirebaseUtils;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import org.commcare.CommCareTestApplication;
+import org.robolectric.annotation.Config;
+
+@Config(application = CommCareTestApplication.class)
+@RunWith(AndroidJUnit4.class)
+public class FirebaseUtilsTest {
+
+ @Test
+ public void testIsFirebaseEnabled_matchesBuildConfig() {
+ assertEquals(BuildConfig.FIREBASE_ENABLED, FirebaseUtils.isFirebaseEnabled());
+ }
+}