diff --git a/app/src/main/java/org/oppia/android/app/customview/SegmentedCircularProgressView.kt b/app/src/main/java/org/oppia/android/app/customview/SegmentedCircularProgressView.kt index dfb764fa592..8f21c03bd52 100644 --- a/app/src/main/java/org/oppia/android/app/customview/SegmentedCircularProgressView.kt +++ b/app/src/main/java/org/oppia/android/app/customview/SegmentedCircularProgressView.kt @@ -8,10 +8,14 @@ import android.util.AttributeSet import android.util.TypedValue import android.view.View import androidx.core.content.ContextCompat -import androidx.core.text.TextUtilsCompat import androidx.core.view.ViewCompat +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentManager +import javax.inject.Inject import org.oppia.android.R -import java.util.Locale +import org.oppia.android.app.translation.AppLanguageResourceHandler +import org.oppia.android.app.view.ViewComponentFactory +import org.oppia.android.app.view.ViewComponentImpl private const val STROKE_DASH_GAP_IN_DEGREE = 12 @@ -22,10 +26,14 @@ private const val STROKE_DASH_GAP_IN_DEGREE = 12 * Reference: // https://stackoverflow.com/a/39210676 */ class SegmentedCircularProgressView : View { + @Inject + lateinit var resourceHandler: AppLanguageResourceHandler + private var sweepAngle = 0f private var strokeWidth = 0f - private val isRTL = TextUtilsCompat - .getLayoutDirectionFromLocale(Locale.getDefault()) == ViewCompat.LAYOUT_DIRECTION_RTL + private val isRtl by lazy { + resourceHandler.getLayoutDirection() == ViewCompat.LAYOUT_DIRECTION_RTL + } private lateinit var baseRect: RectF private lateinit var chapterFinishedArcPaint: Paint @@ -81,8 +89,16 @@ class SegmentedCircularProgressView : View { } } + override fun onAttachedToWindow() { + super.onAttachedToWindow() + + val viewComponentFactory = FragmentManager.findFragment(this) as ViewComponentFactory + val viewComponent = viewComponentFactory.createViewComponent(this) as ViewComponentImpl + viewComponent.inject(this) + } + override fun onDraw(canvas: Canvas) { - if (isRTL) + if (isRtl) rotationY = 180f super.onDraw(canvas) if (!this::baseRect.isInitialized) { diff --git a/app/src/main/java/org/oppia/android/app/help/faq/FAQListViewModel.kt b/app/src/main/java/org/oppia/android/app/help/faq/FAQListViewModel.kt index f753d852260..da44b6b68d1 100644 --- a/app/src/main/java/org/oppia/android/app/help/faq/FAQListViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/help/faq/FAQListViewModel.kt @@ -6,7 +6,6 @@ import org.oppia.android.app.help.faq.faqItemViewModel.FAQContentViewModel import org.oppia.android.app.help.faq.faqItemViewModel.FAQHeaderViewModel import org.oppia.android.app.help.faq.faqItemViewModel.FAQItemViewModel import org.oppia.android.app.viewmodel.ObservableViewModel -import java.util.Locale import javax.inject.Inject import org.oppia.android.app.translation.AppLanguageResourceHandler diff --git a/app/src/main/java/org/oppia/android/app/hintsandsolution/HintsAndSolutionDialogFragmentPresenter.kt b/app/src/main/java/org/oppia/android/app/hintsandsolution/HintsAndSolutionDialogFragmentPresenter.kt index 2c4bdc5a974..5f7c7bd33ed 100644 --- a/app/src/main/java/org/oppia/android/app/hintsandsolution/HintsAndSolutionDialogFragmentPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/hintsandsolution/HintsAndSolutionDialogFragmentPresenter.kt @@ -22,7 +22,6 @@ import org.oppia.android.util.gcsresource.DefaultResourceBucketName import org.oppia.android.util.parser.html.ExplorationHtmlParserEntityType import org.oppia.android.util.parser.html.HtmlParser import java.lang.IllegalStateException -import java.util.Locale import javax.inject.Inject import org.oppia.android.app.model.WrittenTranslationContext import org.oppia.android.app.translation.AppLanguageResourceHandler diff --git a/app/src/main/java/org/oppia/android/app/player/audio/LanguageDialogFragment.kt b/app/src/main/java/org/oppia/android/app/player/audio/LanguageDialogFragment.kt index 172c0978f9e..33f1576f1c8 100644 --- a/app/src/main/java/org/oppia/android/app/player/audio/LanguageDialogFragment.kt +++ b/app/src/main/java/org/oppia/android/app/player/audio/LanguageDialogFragment.kt @@ -5,7 +5,6 @@ import android.content.Context import android.os.Bundle import androidx.appcompat.app.AlertDialog import androidx.appcompat.view.ContextThemeWrapper -import androidx.fragment.app.DialogFragment import org.oppia.android.R import java.util.Locale import kotlin.collections.ArrayList @@ -59,6 +58,7 @@ class LanguageDialogFragment : InjectableDialogFragment() { if (languageCode == "hi-en") { languageNameArrayList.add("Hinglish") } else { + // TODO(#3791): Remove this dependency. val locale = Locale(languageCode) val name = locale.getDisplayLanguage(locale) languageNameArrayList.add(name) diff --git a/app/src/main/java/org/oppia/android/app/translation/AppLanguageResourceHandler.kt b/app/src/main/java/org/oppia/android/app/translation/AppLanguageResourceHandler.kt index 90f642b106e..77d5aef0a0c 100644 --- a/app/src/main/java/org/oppia/android/app/translation/AppLanguageResourceHandler.kt +++ b/app/src/main/java/org/oppia/android/app/translation/AppLanguageResourceHandler.kt @@ -49,6 +49,8 @@ class AppLanguageResourceHandler @Inject constructor( fun computeDateTimeString(timestampMillis: Long): String = getDisplayLocale().computeDateTimeString(timestampMillis) + fun getLayoutDirection(): Int = getDisplayLocale().getLayoutDirection() + private fun getDisplayLocale(): OppiaLocale.DisplayLocale = appLanguageLocaleHandler.getDisplayLocale() } diff --git a/app/src/main/java/org/oppia/android/app/view/ViewComponentImpl.kt b/app/src/main/java/org/oppia/android/app/view/ViewComponentImpl.kt index 06a928361fd..7836d64ff4b 100644 --- a/app/src/main/java/org/oppia/android/app/view/ViewComponentImpl.kt +++ b/app/src/main/java/org/oppia/android/app/view/ViewComponentImpl.kt @@ -4,6 +4,7 @@ import android.view.View import dagger.BindsInstance import dagger.Subcomponent import org.oppia.android.app.customview.LessonThumbnailImageView +import org.oppia.android.app.customview.SegmentedCircularProgressView import org.oppia.android.app.home.promotedlist.ComingSoonTopicsListView import org.oppia.android.app.home.promotedlist.PromotedStoryListView import org.oppia.android.app.player.state.DragDropSortInteractionView @@ -30,4 +31,5 @@ interface ViewComponentImpl: ViewComponent { fun inject(imageRegionSelectionInteractionView: ImageRegionSelectionInteractionView) fun inject(lessonThumbnailImageView: LessonThumbnailImageView) fun inject(promotedStoryListView: PromotedStoryListView) + fun inject(segmentedCircularProgressView: SegmentedCircularProgressView) } diff --git a/app/src/sharedTest/java/org/oppia/android/app/administratorcontrols/AppVersionActivityTest.kt b/app/src/sharedTest/java/org/oppia/android/app/administratorcontrols/AppVersionActivityTest.kt index c06a54996b2..10b71f1e213 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/administratorcontrols/AppVersionActivityTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/administratorcontrols/AppVersionActivityTest.kt @@ -230,6 +230,8 @@ class AppVersionActivityTest { } } + // TODO(#3792): Remove this usage of Locale (probably by introducing a test utility in the locale + // package to generate these strings). private fun getDateTime(dateTimeTimestamp: Long): String? { return oppiaDateTimeFormatter.formatDateFromDateString( OppiaDateTimeFormatter.DD_MMM_YYYY, diff --git a/app/src/sharedTest/java/org/oppia/android/app/player/audio/AudioFragmentTest.kt b/app/src/sharedTest/java/org/oppia/android/app/player/audio/AudioFragmentTest.kt index 79e2fcc9427..6b9665a0f07 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/player/audio/AudioFragmentTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/player/audio/AudioFragmentTest.kt @@ -313,6 +313,7 @@ class AudioFragmentTest { testCoroutineDispatchers.runCurrent() onView(withId(R.id.audio_language_icon)).perform(click()) + // TODO(#3791): Remove this dependency. val locale = Locale("es") testCoroutineDispatchers.runCurrent() diff --git a/app/src/sharedTest/java/org/oppia/android/app/splash/SplashActivityTest.kt b/app/src/sharedTest/java/org/oppia/android/app/splash/SplashActivityTest.kt index b256d050eb5..8d36571cae9 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/splash/SplashActivityTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/splash/SplashActivityTest.kt @@ -108,6 +108,8 @@ class SplashActivityTest { @Inject lateinit var fakeMetaDataRetriever: FakeExpirationMetaDataRetriever + // TODO(#3792): Remove this usage of Locale (probably by introducing a test utility in the locale + // package to generate these strings). private val expirationDateFormat by lazy { SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()) } @Before diff --git a/domain/BUILD.bazel b/domain/BUILD.bazel index 3f642a241ba..6e228da6610 100755 --- a/domain/BUILD.bazel +++ b/domain/BUILD.bazel @@ -154,6 +154,7 @@ TEST_DEPS = [ "//third_party:robolectric_android-all", "//utility/src/main/java/org/oppia/android/util/caching/testing:caching_test_module", "//utility/src/main/java/org/oppia/android/util/extensions:context_extensions", + "//utility/src/main/java/org/oppia/android/util/locale:prod_module", "//utility/src/main/java/org/oppia/android/util/networking:debug_module", "//utility/src/main/java/org/oppia/android/util/networking:debug_util_module", ] diff --git a/domain/src/main/java/org/oppia/android/domain/onboarding/AppStartupStateController.kt b/domain/src/main/java/org/oppia/android/domain/onboarding/AppStartupStateController.kt index 39e134f5c3e..061b6c9f875 100644 --- a/domain/src/main/java/org/oppia/android/domain/onboarding/AppStartupStateController.kt +++ b/domain/src/main/java/org/oppia/android/domain/onboarding/AppStartupStateController.kt @@ -1,5 +1,7 @@ package org.oppia.android.domain.onboarding +import javax.inject.Inject +import javax.inject.Singleton import org.oppia.android.app.model.AppStartupState import org.oppia.android.app.model.AppStartupState.StartupMode import org.oppia.android.app.model.OnboardingState @@ -7,13 +9,8 @@ import org.oppia.android.data.persistence.PersistentCacheStore import org.oppia.android.domain.oppialogger.OppiaLogger import org.oppia.android.util.data.DataProvider import org.oppia.android.util.data.DataProviders.Companion.transform -import java.text.ParseException -import java.text.SimpleDateFormat -import java.util.Date -import java.util.Locale -import javax.inject.Inject -import javax.inject.Singleton import org.oppia.android.util.extensions.getStringFromBundle +import org.oppia.android.util.locale.OppiaLocale private const val APP_STARTUP_STATE_DATA_PROVIDER_ID = "app_startup_state_data_provider_id" @@ -22,10 +19,9 @@ private const val APP_STARTUP_STATE_DATA_PROVIDER_ID = "app_startup_state_data_p class AppStartupStateController @Inject constructor( cacheStoreFactory: PersistentCacheStore.Factory, private val oppiaLogger: OppiaLogger, - private val expirationMetaDataRetriever: ExpirationMetaDataRetriever + private val expirationMetaDataRetriever: ExpirationMetaDataRetriever, + private val machineLocale: OppiaLocale.MachineLocale ) { - private val expirationDateFormat by lazy { SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()) } - private val onboardingFlowStore = cacheStoreFactory.create("on_boarding_flow", OnboardingState.getDefaultInstance()) @@ -88,18 +84,9 @@ class AppStartupStateController @Inject constructor( ) ?: true return if (isAppExpirationEnabled) { val expirationDateString = applicationMetadata?.getStringFromBundle("expiration_date") - val expirationDate = expirationDateString?.let { parseDate(it) } + val expirationDate = expirationDateString?.let { machineLocale.parseOppiaDate(it) } // Assume the app is in an expired state if something fails when comparing the date. - expirationDate?.before(Date()) ?: true + expirationDate?.isBeforeToday() ?: true } else false } - - private fun parseDate(dateString: String): Date? { - return try { - expirationDateFormat.parse(dateString) - } catch (e: ParseException) { - oppiaLogger.e("DOMAIN", "Failed to parse date string: $dateString", e) - null - } - } } diff --git a/domain/src/test/java/org/oppia/android/domain/onboarding/AppStartupStateControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/onboarding/AppStartupStateControllerTest.kt index d3e75dbe3d7..78b0e04369c 100644 --- a/domain/src/test/java/org/oppia/android/domain/onboarding/AppStartupStateControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/onboarding/AppStartupStateControllerTest.kt @@ -14,6 +14,13 @@ import dagger.BindsInstance import dagger.Component import dagger.Module import dagger.Provides +import java.text.SimpleDateFormat +import java.time.Duration +import java.time.Instant +import java.util.Date +import java.util.Locale +import javax.inject.Inject +import javax.inject.Singleton import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith @@ -40,20 +47,15 @@ import org.oppia.android.util.data.AsyncResult import org.oppia.android.util.data.DataProviders.Companion.toLiveData import org.oppia.android.util.data.DataProvidersInjector import org.oppia.android.util.data.DataProvidersInjectorProvider +import org.oppia.android.util.locale.MachineLocaleModule import org.oppia.android.util.logging.EnableConsoleLog import org.oppia.android.util.logging.EnableFileLog import org.oppia.android.util.logging.GlobalLogLevel import org.oppia.android.util.logging.LogLevel import org.oppia.android.util.networking.NetworkConnectionUtilDebugModule +import org.oppia.android.util.system.OppiaClockModule import org.robolectric.Shadows.shadowOf import org.robolectric.annotation.Config -import java.text.SimpleDateFormat -import java.time.Duration -import java.time.Instant -import java.util.Date -import java.util.Locale -import javax.inject.Inject -import javax.inject.Singleton /** Tests for [AppStartupStateController]. */ @RunWith(AndroidJUnit4::class) @@ -85,6 +87,8 @@ class AppStartupStateControllerTest { @Captor lateinit var appStartupStateCaptor: ArgumentCaptor> + // TODO(#3792): Remove this usage of Locale (probably by introducing a test utility in the locale + // package to generate these strings). private val expirationDateFormat by lazy { SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()) } @Test @@ -431,6 +435,7 @@ class AppStartupStateControllerTest { LogStorageModule::class, RobolectricModule::class, TestModule::class, TestDispatcherModule::class, TestLogReportingModule::class, NetworkConnectionUtilDebugModule::class, + OppiaClockModule::class, MachineLocaleModule::class, ExpirationMetaDataRetrieverModule::class // Use real implementation to test closer to prod. ] ) diff --git a/scripts/assets/file_content_validation_checks.textproto b/scripts/assets/file_content_validation_checks.textproto index f44621f69ad..c6470d7f786 100644 --- a/scripts/assets/file_content_validation_checks.textproto +++ b/scripts/assets/file_content_validation_checks.textproto @@ -170,3 +170,47 @@ file_content_checks { prohibited_content_regex: "android:configChanges" failure_message: "Never explicitly handle configuration changes. Instead, use saved instance states for retaining state across rotations. For other types of configuration changes, follow up with the developer mailing list with how to proceed if you think this is a legitimate case." } +file_content_checks { + file_path_regex: ".+?.kt" + prohibited_content_regex: "java\\.util\\.Calendar" + failure_message: "Don't use Calendar directly. Instead, use OppiaClock and/or OppiaLocale for calendar-specific operations." + exempted_file_name: "testing/src/main/java/org/oppia/android/testing/time/FakeOppiaClock.kt" + exempted_file_name: "testing/src/test/java/org/oppia/android/testing/time/FakeOppiaClockTest.kt" + exempted_file_name: "utility/src/main/java/org/oppia/android/util/locale/MachineLocaleImpl.kt" + exempted_file_name: "utility/src/main/java/org/oppia/android/util/system/OppiaClock.kt" +} +file_content_checks { + file_path_regex: ".+?.kt" + prohibited_content_regex: "java\\.util\\.Date" + failure_message: "Don't use Date directly. Instead, perform date-based operations using OppiaLocale." + exempted_file_name: "app/src/sharedTest/java/org/oppia/android/app/splash/SplashActivityTest.kt" + exempted_file_name: "domain/src/main/java/org/oppia/android/domain/locale/DisplayLocaleImpl.kt" + exempted_file_name: "domain/src/test/java/org/oppia/android/domain/onboarding/AppStartupStateControllerTest.kt" + exempted_file_name: "testing/src/main/java/org/oppia/android/testing/time/FakeOppiaClock.kt" + exempted_file_name: "utility/src/main/java/org/oppia/android/util/system/OppiaClock.kt" + exempted_file_name: "utility/src/main/java/org/oppia/android/util/locale/MachineLocaleImpl.kt" +} +file_content_checks { + file_path_regex: ".+?.kt" + prohibited_content_regex: "java\\.text" + failure_message: "Don't perform date/time formatting directly. Instead, use OppiaLocale." + exempted_file_name: "app/src/sharedTest/java/org/oppia/android/app/splash/SplashActivityTest.kt" + exempted_file_name: "domain/src/main/java/org/oppia/android/domain/locale/DisplayLocaleImpl.kt" + exempted_file_name: "domain/src/test/java/org/oppia/android/domain/onboarding/AppStartupStateControllerTest.kt" + exempted_file_name: "testing/src/main/java/org/oppia/android/testing/time/FakeOppiaClock.kt" + exempted_file_name: "utility/src/main/java/org/oppia/android/util/locale/MachineLocaleImpl.kt" +} +file_content_checks { + file_path_regex: ".+?.kt" + prohibited_content_regex: "java\\.util\\.Locale" + failure_message: "Don't use Locale directly. Instead, use LocaleController, or OppiaLocale & its subclasses." + exempted_file_name: "app/src/main/java/org/oppia/android/app/player/audio/LanguageDialogFragment.kt" + exempted_file_name: "app/src/sharedTest/java/org/oppia/android/app/administratorcontrols/AppVersionActivityTest.kt" + exempted_file_name: "app/src/sharedTest/java/org/oppia/android/app/player/audio/AudioFragmentTest.kt" + exempted_file_name: "app/src/sharedTest/java/org/oppia/android/app/splash/SplashActivityTest.kt" + exempted_file_patterns: "domain/src/main/java/org/oppia/android/domain/locale/.+?\\.kt" + exempted_file_name: "domain/src/test/java/org/oppia/android/domain/onboarding/AppStartupStateControllerTest.kt" + exempted_file_patterns: "scripts/.+?\\.kt" + exempted_file_patterns: "utility/src/main/java/org/oppia/android/util/locale/.+?\\.kt" + exempted_file_name: "utility/src/main/java/org/oppia/android/util/logging/firebase/FirebaseEventLogger.kt" +} diff --git a/scripts/src/java/org/oppia/android/scripts/ci/ComputeAffectedTests.kt b/scripts/src/java/org/oppia/android/scripts/ci/ComputeAffectedTests.kt index 5aea7c69969..72b976c9b64 100644 --- a/scripts/src/java/org/oppia/android/scripts/ci/ComputeAffectedTests.kt +++ b/scripts/src/java/org/oppia/android/scripts/ci/ComputeAffectedTests.kt @@ -64,7 +64,7 @@ fun main(args: Array) { // Needed since the codebase isn't yet using Kotlin 1.5, so this function isn't available. private fun String.toBooleanStrictOrNull(): Boolean? { - return when (toLowerCase(Locale.getDefault())) { + return when (toLowerCase(Locale.US)) { "false" -> false "true" -> true else -> null @@ -110,7 +110,7 @@ class ComputeAffectedTests( println("Current branch: ${gitClient.currentBranch}") println("Most recent common commit: ${gitClient.branchMergeBase}") - val currentBranch = gitClient.currentBranch.toLowerCase(Locale.getDefault()) + val currentBranch = gitClient.currentBranch.toLowerCase(Locale.US) val affectedTestTargets = if (computeAllTestsSetting || currentBranch == "develop") { computeAllTestTargets(bazelClient) } else computeAffectedTargetsForNonDevelopBranch(gitClient, bazelClient, rootDirectory) diff --git a/utility/src/main/java/org/oppia/android/util/logging/BUILD.bazel b/utility/src/main/java/org/oppia/android/util/logging/BUILD.bazel index c5bf2a82261..3ea1f8bbe89 100644 --- a/utility/src/main/java/org/oppia/android/util/logging/BUILD.bazel +++ b/utility/src/main/java/org/oppia/android/util/logging/BUILD.bazel @@ -27,6 +27,7 @@ kt_android_library( ":log_level", "//third_party:javax_inject_javax_inject", "//third_party:org_jetbrains_kotlinx_kotlinx-coroutines-core", + "//utility/src/main/java/org/oppia/android/util/locale:oppia_locale", "//utility/src/main/java/org/oppia/android/util/threading:annotations", ], ) diff --git a/utility/src/main/java/org/oppia/android/util/logging/ConsoleLogger.kt b/utility/src/main/java/org/oppia/android/util/logging/ConsoleLogger.kt index f7f904e47f0..5e905b2be41 100644 --- a/utility/src/main/java/org/oppia/android/util/logging/ConsoleLogger.kt +++ b/utility/src/main/java/org/oppia/android/util/logging/ConsoleLogger.kt @@ -7,9 +7,9 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch import org.oppia.android.util.threading.BlockingDispatcher import java.io.File -import java.util.Calendar import javax.inject.Inject import javax.inject.Singleton +import org.oppia.android.util.locale.OppiaLocale /** Wrapper class for Android logcat and file logging. All logs in the app should use this class. */ @Singleton @@ -18,7 +18,8 @@ class ConsoleLogger @Inject constructor( @BlockingDispatcher private val blockingDispatcher: CoroutineDispatcher, @EnableConsoleLog private val enableConsoleLog: Boolean, @EnableFileLog private val enableFileLog: Boolean, - @GlobalLogLevel private val globalLogLevel: LogLevel + @GlobalLogLevel private val globalLogLevel: LogLevel, + private val machineLocale: OppiaLocale.MachineLocale ) { private val blockingScope = CoroutineScope(blockingDispatcher) private val logDirectory = File(context.filesDir, "oppia_app.log") @@ -93,7 +94,9 @@ class ConsoleLogger @Inject constructor( Log.println(logLevel.logLevel, tag, fullLog) } if (enableFileLog) { - logToFileInBackground("${Calendar.getInstance().time}\t${logLevel.name}/$tag: $fullLog") + logToFileInBackground( + "${machineLocale.computeCurrentTimeString()}\t${logLevel.name}/$tag: $fullLog" + ) } } diff --git a/utility/src/main/java/org/oppia/android/util/logging/firebase/FirebaseEventLogger.kt b/utility/src/main/java/org/oppia/android/util/logging/firebase/FirebaseEventLogger.kt index cfaecc282db..8f1aa539d51 100644 --- a/utility/src/main/java/org/oppia/android/util/logging/firebase/FirebaseEventLogger.kt +++ b/utility/src/main/java/org/oppia/android/util/logging/firebase/FirebaseEventLogger.kt @@ -28,6 +28,7 @@ class FirebaseEventLogger( override fun logEvent(eventLog: EventLog) { bundle = eventBundleCreator.createEventBundle(eventLog) firebaseAnalytics.logEvent(eventLog.actionName.toString(), bundle) + // TODO(#3792): Remove this usage of Locale. firebaseAnalytics.setUserProperty(COUNTRY_USER_PROPERTY, Locale.getDefault().displayCountry) firebaseAnalytics.setUserProperty( NETWORK_USER_PROPERTY, connectivityManager.activeNetworkInfo.typeName