Restore Firebase RemoteConfig

pull/1817/head
Alex Baker 4 years ago
parent 2aee91a04b
commit 2c189f9610

@ -234,6 +234,7 @@ dependencies {
googleplayImplementation("com.google.firebase:firebase-analytics:${Versions.analytics}") { googleplayImplementation("com.google.firebase:firebase-analytics:${Versions.analytics}") {
exclude("com.google.android.gms", "play-services-ads-identifier") exclude("com.google.android.gms", "play-services-ads-identifier")
} }
googleplayImplementation("com.google.firebase:firebase-config-ktx:${Versions.remote_config}")
googleplayImplementation("com.google.android.gms:play-services-location:19.0.1") googleplayImplementation("com.google.android.gms:play-services-location:19.0.1")
googleplayImplementation("com.google.android.gms:play-services-maps:18.0.2") googleplayImplementation("com.google.android.gms:play-services-maps:18.0.2")
googleplayImplementation("com.android.billingclient:billing-ktx:3.0.3") googleplayImplementation("com.android.billingclient:billing-ktx:3.0.3")

@ -7,5 +7,7 @@ import javax.inject.Inject
class Firebase @Inject constructor() { class Firebase @Inject constructor() {
fun reportException(t: Throwable) = Timber.e(t) fun reportException(t: Throwable) = Timber.e(t)
fun updateRemoteConfig() {}
fun logEvent(event: Int, vararg params: Pair<Int, Any>) {} fun logEvent(event: Int, vararg params: Pair<Int, Any>) {}
} }

@ -5,10 +5,14 @@ import android.os.Bundle
import androidx.annotation.StringRes import androidx.annotation.StringRes
import com.google.firebase.analytics.FirebaseAnalytics import com.google.firebase.analytics.FirebaseAnalytics
import com.google.firebase.crashlytics.FirebaseCrashlytics import com.google.firebase.crashlytics.FirebaseCrashlytics
import com.google.firebase.remoteconfig.FirebaseRemoteConfig
import com.google.firebase.remoteconfig.ktx.remoteConfigSettings
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import org.tasks.R import org.tasks.R
import org.tasks.jobs.WorkManager
import org.tasks.preferences.Preferences import org.tasks.preferences.Preferences
import timber.log.Timber import timber.log.Timber
import java.util.concurrent.TimeUnit
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -20,6 +24,7 @@ class Firebase @Inject constructor(
private var crashlytics: FirebaseCrashlytics? = null private var crashlytics: FirebaseCrashlytics? = null
private var analytics: FirebaseAnalytics? = null private var analytics: FirebaseAnalytics? = null
private var remoteConfig: FirebaseRemoteConfig? = null
fun reportException(t: Throwable) { fun reportException(t: Throwable) {
Timber.e(t) Timber.e(t)
@ -35,6 +40,12 @@ class Firebase @Inject constructor(
) )
} }
fun updateRemoteConfig() {
remoteConfig?.fetchAndActivate()?.addOnSuccessListener {
Timber.d(it.toString())
}
}
fun logEvent(@StringRes event: Int, vararg p: Pair<Int, Any>) { fun logEvent(@StringRes event: Int, vararg p: Pair<Int, Any>) {
analytics?.logEvent(context.getString(event), Bundle().apply { analytics?.logEvent(context.getString(event), Bundle().apply {
p.forEach { p.forEach {
@ -48,6 +59,9 @@ class Firebase @Inject constructor(
}) })
} }
val reviewCooldown: Long
get() = remoteConfig?.getLong("review_cooldown") ?: 14L
init { init {
if (preferences.isTrackingEnabled) { if (preferences.isTrackingEnabled) {
analytics = FirebaseAnalytics.getInstance(context).apply { analytics = FirebaseAnalytics.getInstance(context).apply {
@ -56,6 +70,13 @@ class Firebase @Inject constructor(
crashlytics = FirebaseCrashlytics.getInstance().apply { crashlytics = FirebaseCrashlytics.getInstance().apply {
setCrashlyticsCollectionEnabled(true) setCrashlyticsCollectionEnabled(true)
} }
remoteConfig = FirebaseRemoteConfig.getInstance().apply {
setConfigSettingsAsync(remoteConfigSettings {
minimumFetchIntervalInSeconds =
TimeUnit.HOURS.toSeconds(WorkManager.REMOTE_CONFIG_INTERVAL_HOURS)
})
setDefaultsAsync(R.xml.remote_config_defaults)
}
} }
} }
} }

@ -9,6 +9,7 @@ import com.google.android.play.core.ktx.requestReview
import com.google.android.play.core.review.ReviewManagerFactory import com.google.android.play.core.review.ReviewManagerFactory
import com.todoroo.andlib.utility.DateUtilities.now import com.todoroo.andlib.utility.DateUtilities.now
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import org.tasks.analytics.Firebase
import org.tasks.preferences.Preferences import org.tasks.preferences.Preferences
import org.tasks.time.DateTimeUtils.printTimestamp import org.tasks.time.DateTimeUtils.printTimestamp
import timber.log.Timber import timber.log.Timber
@ -18,16 +19,22 @@ import javax.inject.Inject
class PlayServices @Inject constructor( class PlayServices @Inject constructor(
@ApplicationContext private val context: Context, @ApplicationContext private val context: Context,
private val preferences: Preferences, private val preferences: Preferences,
private val firebase: Firebase,
) { ) {
fun isAvailable() = fun isAvailable() =
getInstance().isGooglePlayServicesAvailable(context) == ConnectionResult.SUCCESS getInstance().isGooglePlayServicesAvailable(context) == ConnectionResult.SUCCESS
suspend fun requestReview(activity: Activity) { suspend fun requestReview(activity: Activity) {
val now = now() val now = now()
val installCutoff = preferences.installDate + INSTALL_COOLDOWN
val reviewCutoff = preferences.lastReviewRequest + REVIEW_COOLDOWN val reviewCutoff = preferences.lastReviewRequest + REVIEW_COOLDOWN
if (reviewCutoff > now) {
Timber.d("review cooldown: ${printTimestamp(reviewCutoff)}")
return
}
val installCutoff =
preferences.installDate + TimeUnit.DAYS.toMillis(firebase.reviewCooldown)
if (installCutoff > now || reviewCutoff > now) { if (installCutoff > now || reviewCutoff > now) {
Timber.d("wait for review request: install=${printTimestamp(installCutoff)} review=${printTimestamp(reviewCutoff)}") Timber.d("install cooldown: ${printTimestamp(installCutoff)}")
return return
} }
try { try {
@ -42,7 +49,6 @@ class PlayServices @Inject constructor(
} }
companion object { companion object {
private val INSTALL_COOLDOWN = TimeUnit.DAYS.toMillis(14)
private val REVIEW_COOLDOWN = TimeUnit.DAYS.toMillis(30) private val REVIEW_COOLDOWN = TimeUnit.DAYS.toMillis(30)
} }
} }

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<defaultsMap xmlns:tools="http://schemas.android.com/tools"
tools:ignore="MissingDefaultResource">
<entry>
<key>review_cooldown</key>
<value>14</value>
</entry>
</defaultsMap>

@ -82,6 +82,7 @@ class Tasks : Application(), Configuration.Provider {
updateBackgroundSync() updateBackgroundSync()
scheduleMidnightRefresh() scheduleMidnightRefresh()
scheduleBackup() scheduleBackup()
scheduleConfigRefresh()
OpenTaskContentObserver.registerObserver(context, contentObserver.get()) OpenTaskContentObserver.registerObserver(context, contentObserver.get())
updatePurchases() updatePurchases()
} }

@ -0,0 +1,21 @@
package org.tasks.jobs
import android.content.Context
import androidx.hilt.work.HiltWorker
import androidx.work.WorkerParameters
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import org.tasks.analytics.Firebase
import org.tasks.injection.BaseWorker
@HiltWorker
class RemoteConfigWork @AssistedInject constructor(
@Assisted context: Context,
@Assisted workerParams: WorkerParameters,
firebase: Firebase) : BaseWorker(context, workerParams, firebase) {
override suspend fun run(): Result {
firebase.updateRemoteConfig()
return Result.success()
}
}

@ -2,6 +2,7 @@ package org.tasks.jobs
import android.net.Uri import android.net.Uri
import com.todoroo.astrid.data.Task import com.todoroo.astrid.data.Task
import org.tasks.BuildConfig
import org.tasks.data.CaldavAccount import org.tasks.data.CaldavAccount
import org.tasks.data.Place import org.tasks.data.Place
@ -35,6 +36,8 @@ interface WorkManager {
fun scheduleBackup() fun scheduleBackup()
fun scheduleConfigRefresh()
fun scheduleDriveUpload(uri: Uri, purge: Boolean) fun scheduleDriveUpload(uri: Uri, purge: Boolean)
fun cancelNotifications() fun cancelNotifications()
@ -42,6 +45,7 @@ interface WorkManager {
fun updatePurchases() fun updatePurchases()
companion object { companion object {
val REMOTE_CONFIG_INTERVAL_HOURS = if (BuildConfig.DEBUG) 1 else 12.toLong()
const val MAX_CLEANUP_LENGTH = 500 const val MAX_CLEANUP_LENGTH = 500
const val TAG_BACKUP = "tag_backup" const val TAG_BACKUP = "tag_backup"
const val TAG_REFRESH = "tag_refresh" const val TAG_REFRESH = "tag_refresh"
@ -54,6 +58,7 @@ interface WorkManager {
const val TAG_BACKGROUND_SYNC_CALDAV = "tag_background_sync_caldav" const val TAG_BACKGROUND_SYNC_CALDAV = "tag_background_sync_caldav"
const val TAG_BACKGROUND_SYNC_ETEBASE = "tag_background_sync_etebase" const val TAG_BACKGROUND_SYNC_ETEBASE = "tag_background_sync_etebase"
const val TAG_BACKGROUND_SYNC_OPENTASKS = "tag_background_sync_opentasks" const val TAG_BACKGROUND_SYNC_OPENTASKS = "tag_background_sync_opentasks"
const val TAG_REMOTE_CONFIG = "tag_remote_config"
const val TAG_MIGRATE_LOCAL = "tag_migrate_local" const val TAG_MIGRATE_LOCAL = "tag_migrate_local"
const val TAG_UPDATE_PURCHASES = "tag_update_purchases" const val TAG_UPDATE_PURCHASES = "tag_update_purchases"
} }

@ -39,6 +39,7 @@ import org.tasks.jobs.MigrateLocalWork.Companion.EXTRA_ACCOUNT
import org.tasks.jobs.SyncWork.Companion.EXTRA_BACKGROUND import org.tasks.jobs.SyncWork.Companion.EXTRA_BACKGROUND
import org.tasks.jobs.SyncWork.Companion.EXTRA_IMMEDIATE import org.tasks.jobs.SyncWork.Companion.EXTRA_IMMEDIATE
import org.tasks.jobs.WorkManager.Companion.MAX_CLEANUP_LENGTH import org.tasks.jobs.WorkManager.Companion.MAX_CLEANUP_LENGTH
import org.tasks.jobs.WorkManager.Companion.REMOTE_CONFIG_INTERVAL_HOURS
import org.tasks.jobs.WorkManager.Companion.TAG_BACKGROUND_SYNC_CALDAV import org.tasks.jobs.WorkManager.Companion.TAG_BACKGROUND_SYNC_CALDAV
import org.tasks.jobs.WorkManager.Companion.TAG_BACKGROUND_SYNC_ETEBASE import org.tasks.jobs.WorkManager.Companion.TAG_BACKGROUND_SYNC_ETEBASE
import org.tasks.jobs.WorkManager.Companion.TAG_BACKGROUND_SYNC_GOOGLE_TASKS import org.tasks.jobs.WorkManager.Companion.TAG_BACKGROUND_SYNC_GOOGLE_TASKS
@ -47,6 +48,7 @@ import org.tasks.jobs.WorkManager.Companion.TAG_BACKUP
import org.tasks.jobs.WorkManager.Companion.TAG_MIDNIGHT_REFRESH import org.tasks.jobs.WorkManager.Companion.TAG_MIDNIGHT_REFRESH
import org.tasks.jobs.WorkManager.Companion.TAG_MIGRATE_LOCAL import org.tasks.jobs.WorkManager.Companion.TAG_MIGRATE_LOCAL
import org.tasks.jobs.WorkManager.Companion.TAG_REFRESH import org.tasks.jobs.WorkManager.Companion.TAG_REFRESH
import org.tasks.jobs.WorkManager.Companion.TAG_REMOTE_CONFIG
import org.tasks.jobs.WorkManager.Companion.TAG_SYNC_CALDAV import org.tasks.jobs.WorkManager.Companion.TAG_SYNC_CALDAV
import org.tasks.jobs.WorkManager.Companion.TAG_SYNC_ETEBASE import org.tasks.jobs.WorkManager.Companion.TAG_SYNC_ETEBASE
import org.tasks.jobs.WorkManager.Companion.TAG_SYNC_GOOGLE_TASKS import org.tasks.jobs.WorkManager.Companion.TAG_SYNC_GOOGLE_TASKS
@ -225,6 +227,18 @@ class WorkManagerImpl constructor(
.millis .millis
.coerceAtMost(midnight())) .coerceAtMost(midnight()))
override fun scheduleConfigRefresh() {
throttle.run {
workManager.enqueueUniquePeriodicWork(
TAG_REMOTE_CONFIG,
ExistingPeriodicWorkPolicy.KEEP,
PeriodicWorkRequest.Builder(
RemoteConfigWork::class.java, REMOTE_CONFIG_INTERVAL_HOURS, TimeUnit.HOURS)
.setConstraints(networkConstraints)
.build())
}
}
override fun scheduleDriveUpload(uri: Uri, purge: Boolean) { override fun scheduleDriveUpload(uri: Uri, purge: Boolean) {
if (!preferences.getBoolean(R.string.p_google_drive_backup, false)) { if (!preferences.getBoolean(R.string.p_google_drive_backup, false)) {
return return

@ -424,7 +424,6 @@
<string name="event_whats_new">whats_new</string> <string name="event_whats_new">whats_new</string>
<string name="param_whats_new_display_rate">display_rate</string> <string name="param_whats_new_display_rate">display_rate</string>
<string name="param_whats_new_display_subscribe">display_subscribe</string> <string name="param_whats_new_display_subscribe">display_subscribe</string>
<string name="param_user_no_churn">user_no_churn</string>
<string name="param_user_pro">user_pro</string> <string name="param_user_pro">user_pro</string>
<string name="param_click">click</string> <string name="param_click">click</string>
<string name="event_purchase_result">billing_flow_result</string> <string name="event_purchase_result">billing_flow_result</string>

@ -8,6 +8,7 @@ object Versions {
const val room = "2.4.2" const val room = "2.4.2"
const val crashlytics = "18.2.8" const val crashlytics = "18.2.8"
const val analytics = "20.1.0" const val analytics = "20.1.0"
const val remote_config = "21.0.1"
const val okhttp = "4.9.3" const val okhttp = "4.9.3"
const val flipper = "0.136.0" const val flipper = "0.136.0"
const val mockito = "3.9.0" const val mockito = "3.9.0"

@ -201,6 +201,31 @@
+| +--- com.google.android.gms:play-services-basement:18.0.0 (*) +| +--- com.google.android.gms:play-services-basement:18.0.0 (*)
+| +--- com.google.android.gms:play-services-measurement-base:20.1.0 (*) +| +--- com.google.android.gms:play-services-measurement-base:20.1.0 (*)
+| \--- com.google.android.gms:play-services-measurement-impl:20.1.0 (*) +| \--- com.google.android.gms:play-services-measurement-impl:20.1.0 (*)
++--- com.google.firebase:firebase-config-ktx:21.0.1
+| +--- androidx.annotation:annotation:1.1.0 -> 1.3.0
+| +--- com.google.firebase:firebase-abt:21.0.0
+| | +--- com.google.android.gms:play-services-basement:17.0.0 -> 18.0.0 (*)
+| | +--- com.google.firebase:firebase-common:20.0.0 (*)
+| | +--- com.google.firebase:firebase-components:17.0.0 (*)
+| | \--- com.google.firebase:firebase-measurement-connector:18.0.0 -> 19.0.0 (*)
+| +--- com.google.firebase:firebase-common:20.0.0 (*)
+| +--- com.google.firebase:firebase-common-ktx:20.0.0
+| | +--- androidx.annotation:annotation:1.1.0 -> 1.3.0
+| | +--- com.google.firebase:firebase-common:20.0.0 (*)
+| | +--- com.google.firebase:firebase-components:17.0.0 (*)
+| | \--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.72 -> 1.6.10 (*)
+| +--- com.google.firebase:firebase-components:17.0.0 (*)
+| +--- com.google.firebase:firebase-config:21.0.1
+| | +--- com.google.android.gms:play-services-tasks:17.0.2 -> 18.0.1 (*)
+| | +--- com.google.firebase:firebase-abt:21.0.0 (*)
+| | +--- com.google.firebase:firebase-common:20.0.0 (*)
+| | +--- com.google.firebase:firebase-components:17.0.0 (*)
+| | +--- com.google.firebase:firebase-installations:17.0.0 (*)
+| | +--- com.google.firebase:firebase-installations-interop:17.0.0 (*)
+| | \--- com.google.firebase:firebase-measurement-connector:18.0.0 -> 19.0.0 (*)
+| +--- com.google.firebase:firebase-installations:17.0.0 (*)
+| +--- com.google.firebase:firebase-installations-interop:17.0.0 (*)
+| \--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.72 -> 1.6.10 (*)
++--- com.google.android.gms:play-services-location:19.0.1 ++--- com.google.android.gms:play-services-location:19.0.1
+| +--- com.google.android.gms:play-services-base:18.0.1 +| +--- com.google.android.gms:play-services-base:18.0.1
+| | +--- androidx.collection:collection:1.0.0 -> 1.1.0 (*) +| | +--- androidx.collection:collection:1.0.0 -> 1.1.0 (*)

Loading…
Cancel
Save