package com.thebluealliance.androidclient.config; import com.google.android.gms.tasks.OnCompleteListener; import com.google.android.gms.tasks.Task; import com.google.android.gms.tasks.Tasks; import com.google.firebase.remoteconfig.FirebaseRemoteConfig; import com.google.firebase.remoteconfig.FirebaseRemoteConfigFetchException; import com.google.firebase.remoteconfig.FirebaseRemoteConfigFetchThrottledException; import com.thebluealliance.androidclient.Analytics; import com.thebluealliance.androidclient.TbaLogger; import com.thebluealliance.androidclient.datafeed.APIv3RequestInterceptor; import android.content.SharedPreferences; import android.support.annotation.WorkerThread; import java.util.concurrent.ExecutionException; import javax.annotation.Nullable; import javax.inject.Inject; public class AppConfig { private static final long CACHE_EXIPIRATION = 3600; // One hour in seconds private final @Nullable FirebaseRemoteConfig mFirebaseRemoteConfig; private final SharedPreferences mPrefs; private Task<Void> mActiveTask; @Inject public AppConfig(@Nullable FirebaseRemoteConfig firebaseRemoteConfig, SharedPreferences prefs) { mFirebaseRemoteConfig = firebaseRemoteConfig; mPrefs = prefs; mActiveTask = null; } public String getString(String key) { if (mFirebaseRemoteConfig == null) { return ""; } return mFirebaseRemoteConfig.getString(key); } public boolean getBoolean(String key) { return mFirebaseRemoteConfig != null && mFirebaseRemoteConfig.getBoolean(key); } public long getLong(String key, long defaultValue) { if (mFirebaseRemoteConfig == null) return defaultValue; return mFirebaseRemoteConfig.getLong(key); } public void updateRemoteData() { updateDataInternal(null); } public void updateRemoteData(OnCompleteListener<Void> onCompleteListener) { updateDataInternal(onCompleteListener); } @WorkerThread public void updateRemoteDataBlocking() throws ExecutionException, InterruptedException { updateDataInternal(null); if (mActiveTask != null) { Tasks.await(mActiveTask); } // Wait for the onCompleteHandler to finish while (mActiveTask != null) { Thread.sleep(100); } } private void updateDataInternal(@Nullable OnCompleteListener<Void> onComplete) { if (mFirebaseRemoteConfig == null) { return; } if (mActiveTask != null) { TbaLogger.w("Already updating remote config..."); return; } boolean isDeveloperMode = mFirebaseRemoteConfig.getInfo() .getConfigSettings() .isDeveloperModeEnabled(); TbaLogger.i("Updating remote configuration"); mActiveTask = mFirebaseRemoteConfig.fetch(isDeveloperMode ? 0 : CACHE_EXIPIRATION) .addOnCompleteListener(task -> { if (task.isSuccessful()) { TbaLogger.i("Remote config update succeeded"); mFirebaseRemoteConfig.activateFetched(); /* Update the analytics ID in a static class * This is horrible, nasty, good-for-nothing, hacky, and disgusting * Here, we atone for sins of the past */ Analytics.setAnalyticsId(mFirebaseRemoteConfig.getString(Analytics.PROD_ANALYTICS_KEY)); APIv3RequestInterceptor.updateApiKeys(mFirebaseRemoteConfig, mPrefs); } else { handleUpdateException(task.getException()); } mActiveTask = null; }) .addOnFailureListener(this::handleUpdateException); if (onComplete != null) { mActiveTask.addOnCompleteListener(onComplete); } } private void handleUpdateException(Exception e) { if (e instanceof FirebaseRemoteConfigFetchThrottledException) { TbaLogger.d("RemoteConfig fetch throttled"); } else if (e instanceof FirebaseRemoteConfigFetchException) { TbaLogger.i("Error fetching RemoteConfig: " + e.getMessage()); } else { TbaLogger.w("Error fetching RemoteConfig: " + e.getMessage(), e); } } }