Explicitly disable all feedback, dev info and crash reporting.
Addresses https://github.com/zcash/zcash-android-wallet/issues/143 by placing everything behind a user setting that can be enabled in the future by users who want to continue helping us improve the user experience. For the most part, this will just be turned on for internal company releases in order to continue learning and improving the app.
This commit is contained in:
parent
340fb8c993
commit
de69567812
|
@ -5,8 +5,7 @@ apply plugin: 'kotlin-android'
|
||||||
apply plugin: 'kotlin-android-extensions'
|
apply plugin: 'kotlin-android-extensions'
|
||||||
apply plugin: 'kotlin-kapt'
|
apply plugin: 'kotlin-kapt'
|
||||||
apply plugin: 'com.google.gms.google-services'
|
apply plugin: 'com.google.gms.google-services'
|
||||||
apply plugin: 'io.fabric'
|
apply plugin: 'com.google.firebase.crashlytics'
|
||||||
apply plugin: 'com.google.firebase.firebase-perf'
|
|
||||||
//apply plugin: 'com.github.ben-manes.versions'
|
//apply plugin: 'com.github.ben-manes.versions'
|
||||||
|
|
||||||
archivesBaseName = 'zcash-android-wallet'
|
archivesBaseName = 'zcash-android-wallet'
|
||||||
|
@ -102,10 +101,6 @@ android {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
crashlytics {
|
|
||||||
enableNdk true
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||||
implementation project(':qrecycler')
|
implementation project(':qrecycler')
|
||||||
|
@ -161,9 +156,6 @@ dependencies {
|
||||||
|
|
||||||
// Analytics (for dogfooding/crash-reporting/feedback only on internal team builds)
|
// Analytics (for dogfooding/crash-reporting/feedback only on internal team builds)
|
||||||
implementation Deps.Analytics.CRASHLYTICS
|
implementation Deps.Analytics.CRASHLYTICS
|
||||||
implementation Deps.Analytics.CRASHLYTICS_NDK
|
|
||||||
implementation Deps.Analytics.FIREBASE
|
|
||||||
implementation Deps.Analytics.FIREBASE_PERF
|
|
||||||
implementation Deps.Analytics.MIXPANEL
|
implementation Deps.Analytics.MIXPANEL
|
||||||
|
|
||||||
// Misc.
|
// Misc.
|
||||||
|
|
|
@ -33,6 +33,8 @@
|
||||||
|
|
||||||
<!-- Firebase options -->
|
<!-- Firebase options -->
|
||||||
<meta-data android:name="com.google.firebase.ml.vision.DEPENDENCIES" android:value="barcode" />
|
<meta-data android:name="com.google.firebase.ml.vision.DEPENDENCIES" android:value="barcode" />
|
||||||
|
<!-- All reporting is opt-in, only -->
|
||||||
|
<meta-data android:name="firebase_crashlytics_collection_enabled" android:value="false" />
|
||||||
|
|
||||||
<!-- Mixpanel options -->
|
<!-- Mixpanel options -->
|
||||||
<meta-data android:name="com.mixpanel.android.MPConfig.AutoShowMixpanelUpdates" android:value="false" />
|
<meta-data android:name="com.mixpanel.android.MPConfig.AutoShowMixpanelUpdates" android:value="false" />
|
||||||
|
|
|
@ -37,7 +37,6 @@ class ZcashWalletApp : Application(), CameraXConfig.Provider {
|
||||||
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
Thread.setDefaultUncaughtExceptionHandler(ExceptionReporter(Thread.getDefaultUncaughtExceptionHandler()))
|
Thread.setDefaultUncaughtExceptionHandler(ExceptionReporter(Thread.getDefaultUncaughtExceptionHandler()))
|
||||||
Twig.plant(TroubleshootingTwig())
|
|
||||||
creationTime = System.currentTimeMillis()
|
creationTime = System.currentTimeMillis()
|
||||||
instance = this
|
instance = this
|
||||||
// Setup handler for uncaught exceptions.
|
// Setup handler for uncaught exceptions.
|
||||||
|
|
|
@ -2,9 +2,14 @@ package cash.z.ecc.android.di.module
|
||||||
|
|
||||||
import android.content.ClipboardManager
|
import android.content.ClipboardManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.content.SharedPreferences
|
||||||
import cash.z.ecc.android.ZcashWalletApp
|
import cash.z.ecc.android.ZcashWalletApp
|
||||||
import cash.z.ecc.android.di.component.MainActivitySubcomponent
|
import cash.z.ecc.android.di.component.MainActivitySubcomponent
|
||||||
import cash.z.ecc.android.feedback.*
|
import cash.z.ecc.android.feedback.*
|
||||||
|
import cash.z.ecc.android.sdk.ext.SilentTwig
|
||||||
|
import cash.z.ecc.android.sdk.ext.TroubleshootingTwig
|
||||||
|
import cash.z.ecc.android.sdk.ext.Twig
|
||||||
|
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.Provides
|
import dagger.Provides
|
||||||
import dagger.multibindings.IntoSet
|
import dagger.multibindings.IntoSet
|
||||||
|
@ -27,6 +32,11 @@ class AppModule {
|
||||||
// Feedback
|
// Feedback
|
||||||
//
|
//
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun providePreferences(context: Context): SharedPreferences
|
||||||
|
= context.getSharedPreferences("Application", Context.MODE_PRIVATE)
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
fun provideFeedback(): Feedback = Feedback()
|
fun provideFeedback(): Feedback = Feedback()
|
||||||
|
@ -35,8 +45,16 @@ class AppModule {
|
||||||
@Singleton
|
@Singleton
|
||||||
fun provideFeedbackCoordinator(
|
fun provideFeedbackCoordinator(
|
||||||
feedback: Feedback,
|
feedback: Feedback,
|
||||||
|
preferences: SharedPreferences,
|
||||||
defaultObservers: Set<@JvmSuppressWildcards FeedbackCoordinator.FeedbackObserver>
|
defaultObservers: Set<@JvmSuppressWildcards FeedbackCoordinator.FeedbackObserver>
|
||||||
): FeedbackCoordinator = FeedbackCoordinator(feedback, defaultObservers)
|
): FeedbackCoordinator {
|
||||||
|
return preferences.getBoolean(FeedbackCoordinator.ENABLED, false).let { isEnabled ->
|
||||||
|
// observe nothing unless feedback is enabled
|
||||||
|
FirebaseCrashlytics.getInstance().setCrashlyticsCollectionEnabled(isEnabled)
|
||||||
|
Twig.plant(if (isEnabled) TroubleshootingTwig() else SilentTwig())
|
||||||
|
FeedbackCoordinator(feedback, if (isEnabled) defaultObservers else setOf())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package cash.z.ecc.android.feedback
|
package cash.z.ecc.android.feedback
|
||||||
|
|
||||||
import com.crashlytics.android.Crashlytics
|
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||||
|
|
||||||
class FeedbackCrashlytics : FeedbackCoordinator.FeedbackObserver {
|
class FeedbackCrashlytics : FeedbackCoordinator.FeedbackObserver {
|
||||||
/**
|
/**
|
||||||
|
@ -18,7 +18,7 @@ class FeedbackCrashlytics : FeedbackCoordinator.FeedbackObserver {
|
||||||
)
|
)
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
exception?.let { Crashlytics.logException(it) }
|
exception?.let { FirebaseCrashlytics.getInstance().recordException(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ReorgException(errorHeight: Int, rewindHeight: Int, reorgMesssage: String) :
|
private class ReorgException(errorHeight: Int, rewindHeight: Int, reorgMesssage: String) :
|
||||||
|
|
|
@ -63,6 +63,7 @@ object Report {
|
||||||
val errorHeight: Int by propertyMap
|
val errorHeight: Int by propertyMap
|
||||||
val rewindHeight: Int by propertyMap
|
val rewindHeight: Int by propertyMap
|
||||||
}
|
}
|
||||||
|
class TxUpdateFailed(t: Throwable) : Feedback.AppError("txupdate", t, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,73 +29,75 @@ class TransactionViewHolder<T : ConfirmedTransaction>(itemView: View) : Recycler
|
||||||
private val formatter = SimpleDateFormat("M/d h:mma", Locale.getDefault())
|
private val formatter = SimpleDateFormat("M/d h:mma", Locale.getDefault())
|
||||||
private val addressRegex = """zs\d\w{65,}""".toRegex()
|
private val addressRegex = """zs\d\w{65,}""".toRegex()
|
||||||
|
|
||||||
fun bindTo(transaction: T?) = (itemView.context as MainActivity).lifecycleScope.launch {
|
fun bindTo(transaction: T?) {
|
||||||
// update view
|
(itemView.context as MainActivity).lifecycleScope.launch {
|
||||||
var lineOne: String = ""
|
// update view
|
||||||
var lineTwo: String = ""
|
var lineOne: String = ""
|
||||||
var amountZec: String = ""
|
var lineTwo: String = ""
|
||||||
var amountDisplay: String = ""
|
var amountZec: String = ""
|
||||||
var amountColor: Int = R.color.text_light_dimmed
|
var amountDisplay: String = ""
|
||||||
var lineOneColor: Int = R.color.text_light
|
var amountColor: Int = R.color.text_light_dimmed
|
||||||
var lineTwoColor: Int = R.color.text_light_dimmed
|
var lineOneColor: Int = R.color.text_light
|
||||||
var indicatorBackground: Int = R.drawable.background_indicator_unknown
|
var lineTwoColor: Int = R.color.text_light_dimmed
|
||||||
|
var indicatorBackground: Int = R.drawable.background_indicator_unknown
|
||||||
|
|
||||||
transaction?.apply {
|
transaction?.apply {
|
||||||
itemView.setOnClickListener {
|
itemView.setOnClickListener {
|
||||||
onTransactionClicked(this)
|
onTransactionClicked(this)
|
||||||
}
|
}
|
||||||
itemView.setOnLongClickListener {
|
itemView.setOnLongClickListener {
|
||||||
onTransactionLongPressed(this)
|
onTransactionLongPressed(this)
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
amountZec = value.convertZatoshiToZecString()
|
amountZec = value.convertZatoshiToZecString()
|
||||||
// TODO: these might be good extension functions
|
// TODO: these might be good extension functions
|
||||||
val timestamp = formatter.format(blockTimeInSeconds * 1000L)
|
val timestamp = formatter.format(blockTimeInSeconds * 1000L)
|
||||||
val isMined = blockTimeInSeconds != 0L
|
val isMined = blockTimeInSeconds != 0L
|
||||||
when {
|
when {
|
||||||
!toAddress.isNullOrEmpty() -> {
|
!toAddress.isNullOrEmpty() -> {
|
||||||
lineOne = "You paid ${toAddress?.toAbbreviatedAddress()}"
|
lineOne = "You paid ${toAddress?.toAbbreviatedAddress()}"
|
||||||
lineTwo = if (isMined) "Sent $timestamp" else "Pending confirmation"
|
lineTwo = if (isMined) "Sent $timestamp" else "Pending confirmation"
|
||||||
amountDisplay = "- $amountZec"
|
amountDisplay = "- $amountZec"
|
||||||
if (isMined) {
|
if (isMined) {
|
||||||
amountColor = R.color.zcashRed
|
amountColor = R.color.zcashRed
|
||||||
indicatorBackground = R.drawable.background_indicator_outbound
|
indicatorBackground = R.drawable.background_indicator_outbound
|
||||||
} else {
|
} else {
|
||||||
lineOneColor = R.color.text_light_dimmed
|
lineOneColor = R.color.text_light_dimmed
|
||||||
lineTwoColor = R.color.text_light
|
lineTwoColor = R.color.text_light
|
||||||
|
}
|
||||||
|
}
|
||||||
|
toAddress.isNullOrEmpty() && value > 0L && minedHeight > 0 -> {
|
||||||
|
lineOne = getSender(transaction)
|
||||||
|
lineTwo = "Received $timestamp"
|
||||||
|
amountDisplay = "+ $amountZec"
|
||||||
|
amountColor = R.color.zcashGreen
|
||||||
|
indicatorBackground = R.drawable.background_indicator_inbound
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
lineOne = "Unknown"
|
||||||
|
lineTwo = "Unknown"
|
||||||
|
amountDisplay = "$amountZec"
|
||||||
|
amountColor = R.color.text_light
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
toAddress.isNullOrEmpty() && value > 0L && minedHeight > 0 -> {
|
// sanitize amount
|
||||||
lineOne = getSender(transaction)
|
if (value < ZcashSdk.MINERS_FEE_ZATOSHI) amountDisplay = "< 0.001"
|
||||||
lineTwo = "Received $timestamp"
|
else if (amountZec.length > 10) { // 10 allows 3 digits to the left and 6 to the right of the decimal
|
||||||
amountDisplay = "+ $amountZec"
|
amountDisplay = "tap to view"
|
||||||
amountColor = R.color.zcashGreen
|
|
||||||
indicatorBackground = R.drawable.background_indicator_inbound
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
lineOne = "Unknown"
|
|
||||||
lineTwo = "Unknown"
|
|
||||||
amountDisplay = "$amountZec"
|
|
||||||
amountColor = R.color.text_light
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// sanitize amount
|
|
||||||
if (value < ZcashSdk.MINERS_FEE_ZATOSHI) amountDisplay = "< 0.001"
|
|
||||||
else if (amountZec.length > 10) { // 10 allows 3 digits to the left and 6 to the right of the decimal
|
topText.text = lineOne
|
||||||
amountDisplay = "tap to view"
|
bottomText.text = lineTwo
|
||||||
}
|
amountText.text = amountDisplay
|
||||||
|
amountText.setTextColor(amountColor.toAppColor())
|
||||||
|
topText.setTextColor(lineOneColor.toAppColor())
|
||||||
|
bottomText.setTextColor(lineTwoColor.toAppColor())
|
||||||
|
val context = itemView.context
|
||||||
|
indicator.background = context.resources.getDrawable(indicatorBackground)
|
||||||
|
shieldIcon.goneIf((transaction?.raw != null || transaction?.expiryHeight != null) && !transaction?.toAddress.isShielded())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
topText.text = lineOne
|
|
||||||
bottomText.text = lineTwo
|
|
||||||
amountText.text = amountDisplay
|
|
||||||
amountText.setTextColor(amountColor.toAppColor())
|
|
||||||
topText.setTextColor(lineOneColor.toAppColor())
|
|
||||||
bottomText.setTextColor(lineTwoColor.toAppColor())
|
|
||||||
val context = itemView.context
|
|
||||||
indicator.background = context.resources.getDrawable(indicatorBackground)
|
|
||||||
shieldIcon.goneIf((transaction?.raw != null || transaction?.expiryHeight != null) && !transaction?.toAddress.isShielded())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun getSender(transaction: ConfirmedTransaction): String {
|
private suspend fun getSender(transaction: ConfirmedTransaction): String {
|
||||||
|
|
|
@ -21,8 +21,8 @@ import cash.z.ecc.android.feedback.Report.Tap.SCAN_RECEIVE
|
||||||
import cash.z.ecc.android.sdk.ext.twig
|
import cash.z.ecc.android.sdk.ext.twig
|
||||||
import cash.z.ecc.android.ui.base.BaseFragment
|
import cash.z.ecc.android.ui.base.BaseFragment
|
||||||
import cash.z.ecc.android.ui.send.SendViewModel
|
import cash.z.ecc.android.ui.send.SendViewModel
|
||||||
import com.crashlytics.android.Crashlytics
|
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
import com.google.common.util.concurrent.ListenableFuture
|
||||||
|
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import java.util.concurrent.ExecutorService
|
import java.util.concurrent.ExecutorService
|
||||||
import java.util.concurrent.Executors
|
import java.util.concurrent.Executors
|
||||||
|
@ -102,7 +102,7 @@ class ScanFragment : BaseFragment<FragmentScanBinding>() {
|
||||||
preview.setSurfaceProvider(binding.preview.createSurfaceProvider())
|
preview.setSurfaceProvider(binding.preview.createSurfaceProvider())
|
||||||
} catch (t: Throwable) {
|
} catch (t: Throwable) {
|
||||||
// TODO: consider bubbling this up to the user
|
// TODO: consider bubbling this up to the user
|
||||||
Crashlytics.logException(t)
|
mainActivity?.feedback?.report(t)
|
||||||
twig("Error while opening the camera: $t")
|
twig("Error while opening the camera: $t")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,6 @@ import cash.z.ecc.android.sdk.db.entity.*
|
||||||
import cash.z.ecc.android.sdk.ext.convertZatoshiToZecString
|
import cash.z.ecc.android.sdk.ext.convertZatoshiToZecString
|
||||||
import cash.z.ecc.android.sdk.ext.toAbbreviatedAddress
|
import cash.z.ecc.android.sdk.ext.toAbbreviatedAddress
|
||||||
import cash.z.ecc.android.sdk.ext.twig
|
import cash.z.ecc.android.sdk.ext.twig
|
||||||
import com.crashlytics.android.Crashlytics
|
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.flow
|
import kotlinx.coroutines.flow.flow
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
|
@ -112,8 +111,8 @@ class SendFinalFragment : BaseFragment<FragmentSendFinalBinding>() {
|
||||||
} catch(t: Throwable) {
|
} catch(t: Throwable) {
|
||||||
val message = "ERROR: error while handling pending transaction update! $t"
|
val message = "ERROR: error while handling pending transaction update! $t"
|
||||||
twig(message)
|
twig(message)
|
||||||
Crashlytics.log(message)
|
mainActivity?.feedback?.report(Report.Error.NonFatal.TxUpdateFailed(t))
|
||||||
Crashlytics.logException(t)
|
mainActivity?.feedback?.report(t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,6 @@ import cash.z.ecc.android.sdk.ext.ZcashSdk
|
||||||
import cash.z.ecc.android.sdk.ext.convertZatoshiToZecString
|
import cash.z.ecc.android.sdk.ext.convertZatoshiToZecString
|
||||||
import cash.z.ecc.android.sdk.ext.twig
|
import cash.z.ecc.android.sdk.ext.twig
|
||||||
import cash.z.ecc.android.sdk.validate.AddressType
|
import cash.z.ecc.android.sdk.validate.AddressType
|
||||||
import com.crashlytics.android.Crashlytics
|
|
||||||
import kotlinx.coroutines.Dispatchers.IO
|
import kotlinx.coroutines.Dispatchers.IO
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.flow
|
import kotlinx.coroutines.flow.flow
|
||||||
|
@ -144,7 +143,7 @@ class SendViewModel @Inject constructor() : ViewModel() {
|
||||||
report(metricId)
|
report(metricId)
|
||||||
}
|
}
|
||||||
} catch (t: Throwable) {
|
} catch (t: Throwable) {
|
||||||
Crashlytics.logException(RuntimeException("Error while updating Metrics", t))
|
feedback.report(t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,11 +10,9 @@ import android.widget.TextView
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.activity.addCallback
|
import androidx.activity.addCallback
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import cash.z.ecc.android.R
|
|
||||||
import cash.z.ecc.android.ZcashWalletApp
|
import cash.z.ecc.android.ZcashWalletApp
|
||||||
import cash.z.ecc.android.databinding.FragmentBackupBinding
|
import cash.z.ecc.android.databinding.FragmentBackupBinding
|
||||||
import cash.z.ecc.android.di.viewmodel.activityViewModel
|
import cash.z.ecc.android.di.viewmodel.activityViewModel
|
||||||
import cash.z.ecc.android.di.viewmodel.viewModel
|
|
||||||
import cash.z.ecc.android.feedback.Report
|
import cash.z.ecc.android.feedback.Report
|
||||||
import cash.z.ecc.android.feedback.Report.MetricType.SEED_PHRASE_LOADED
|
import cash.z.ecc.android.feedback.Report.MetricType.SEED_PHRASE_LOADED
|
||||||
import cash.z.ecc.android.feedback.Report.Tap.BACKUP_DONE
|
import cash.z.ecc.android.feedback.Report.Tap.BACKUP_DONE
|
||||||
|
|
|
@ -13,7 +13,7 @@ buildscript {
|
||||||
classpath 'com.google.gms:google-services:4.3.3'
|
classpath 'com.google.gms:google-services:4.3.3'
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${Deps.kotlinVersion}"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${Deps.kotlinVersion}"
|
||||||
classpath 'io.fabric.tools:gradle:1.31.2'
|
classpath 'io.fabric.tools:gradle:1.31.2'
|
||||||
classpath 'com.google.firebase:perf-plugin:1.3.1'
|
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.1.1'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -61,10 +61,7 @@ object Deps {
|
||||||
val STUB = "io.grpc:grpc-stub:$version"
|
val STUB = "io.grpc:grpc-stub:$version"
|
||||||
}
|
}
|
||||||
object Analytics { // for dogfooding/crash-reporting/feedback only on internal team builds
|
object Analytics { // for dogfooding/crash-reporting/feedback only on internal team builds
|
||||||
val CRASHLYTICS = "com.crashlytics.sdk.android:crashlytics:2.10.1"
|
val CRASHLYTICS = "com.google.firebase:firebase-crashlytics:17.0.1"
|
||||||
val CRASHLYTICS_NDK = "com.crashlytics.sdk.android:crashlytics-ndk:2.1.1"
|
|
||||||
val FIREBASE = "com.google.firebase:firebase-analytics:17.4.3"
|
|
||||||
val FIREBASE_PERF = "com.google.firebase:firebase-perf:19.0.7"
|
|
||||||
val MIXPANEL = "com.mixpanel.android:mixpanel-android:5.6.3"
|
val MIXPANEL = "com.mixpanel.android:mixpanel-android:5.6.3"
|
||||||
}
|
}
|
||||||
object JavaX {
|
object JavaX {
|
||||||
|
|
|
@ -125,6 +125,7 @@ class FeedbackCoordinator(val feedback: Feedback, defaultObservers: Set<Feedback
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
const val ENABLED = "setting.feedbackcoordinater.enabled"
|
||||||
private val mutex: Mutex = Mutex()
|
private val mutex: Mutex = Mutex()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue