diff --git a/analytics/src/main/java/io/appmetrica/analytics/impl/AppMetricaConfigForAnonymousActivationProvider.kt b/analytics/src/main/java/io/appmetrica/analytics/impl/AppMetricaConfigForAnonymousActivationProvider.kt index fddf32f4..78ae9c61 100644 --- a/analytics/src/main/java/io/appmetrica/analytics/impl/AppMetricaConfigForAnonymousActivationProvider.kt +++ b/analytics/src/main/java/io/appmetrica/analytics/impl/AppMetricaConfigForAnonymousActivationProvider.kt @@ -1,16 +1,25 @@ package io.appmetrica.analytics.impl -import android.content.Context import io.appmetrica.analytics.AppMetricaConfig import io.appmetrica.analytics.impl.db.preferences.PreferencesClientDbStorage +import io.appmetrica.analytics.logger.appmetrica.internal.DebugLogger internal class AppMetricaConfigForAnonymousActivationProvider( - private val context: Context, private val preferences: PreferencesClientDbStorage ) { + private val tag = "[AppMetricaConfigForAnonymousActivationProvider]" + private val defaultAnonymousConfigProvider = AppMetricaDefaultAnonymousConfigProvider() val config: AppMetricaConfig - get() = preferences.appMetricaConfig ?: defaultAnonymousConfigProvider.getConfig(context) + get() { + val configFromPreferences = preferences.appMetricaConfig + if (configFromPreferences != null) { + DebugLogger.info(tag, "Choose saved config") + return configFromPreferences + } + DebugLogger.info(tag, "Choose default anonymous config") + return defaultAnonymousConfigProvider.getConfig() + } } diff --git a/analytics/src/main/java/io/appmetrica/analytics/impl/AppMetricaDefaultAnonymousConfigProvider.kt b/analytics/src/main/java/io/appmetrica/analytics/impl/AppMetricaDefaultAnonymousConfigProvider.kt index 53502d1f..dc5674ae 100644 --- a/analytics/src/main/java/io/appmetrica/analytics/impl/AppMetricaDefaultAnonymousConfigProvider.kt +++ b/analytics/src/main/java/io/appmetrica/analytics/impl/AppMetricaDefaultAnonymousConfigProvider.kt @@ -1,20 +1,24 @@ package io.appmetrica.analytics.impl -import android.content.Context import io.appmetrica.analytics.AppMetricaConfig -import io.appmetrica.analytics.impl.utils.FirstLaunchDetector import io.appmetrica.analytics.impl.utils.MainProcessDetector +import io.appmetrica.analytics.logger.appmetrica.internal.DebugLogger class AppMetricaDefaultAnonymousConfigProvider { + private val tag = "[AppMetricaDefaultAnonymousConfigProvider]" + private val anonymousApiKey: String = "629a824d-c717-4ba5-bc0f-3f3968554d01" private val mainProcessDetector: MainProcessDetector = ClientServiceLocator.getInstance().mainProcessDetector - private val firstLaunchDetector = FirstLaunchDetector() + private val firstLaunchDetector = ClientServiceLocator.getInstance().firstLaunchDetector - fun getConfig(context: Context): AppMetricaConfig { + fun getConfig(): AppMetricaConfig { val builder = AppMetricaConfig.newConfigBuilder(anonymousApiKey) - if (mainProcessDetector.isMainProcess && firstLaunchDetector.detectNotFirstLaunch(context)) { + if (mainProcessDetector.isMainProcess && firstLaunchDetector.isNotFirstLaunch()) { + DebugLogger.info(tag, "Add handleFirstActivationAsUpdate value to config") builder.handleFirstActivationAsUpdate(true) + } else { + DebugLogger.info(tag, "Use default config") } return builder.build() } diff --git a/analytics/src/main/java/io/appmetrica/analytics/impl/AppMetricaFacade.java b/analytics/src/main/java/io/appmetrica/analytics/impl/AppMetricaFacade.java index 1e6c407c..d5c27d15 100644 --- a/analytics/src/main/java/io/appmetrica/analytics/impl/AppMetricaFacade.java +++ b/analytics/src/main/java/io/appmetrica/analytics/impl/AppMetricaFacade.java @@ -24,7 +24,7 @@ public class AppMetricaFacade implements IReporterFactoryProvider { - private static final String TAG = "[AppMetricaImpl]"; + private static final String TAG = "[AppMetricaFacade]"; @NonNull private final Context mContext; @@ -55,11 +55,14 @@ public AppMetricaFacade(@NonNull final Context context) { } public void init(boolean async) { + ClientServiceLocator clientServiceLocator = ClientServiceLocator.getInstance(); Executor executorForInit = async - ? ClientServiceLocator.getInstance().getClientExecutorProvider().getDefaultExecutor() + ? clientServiceLocator.getClientExecutorProvider().getDefaultExecutor() : new BlockingExecutor(); executorForInit.execute(() -> { + DebugLogger.INSTANCE.info(TAG, "Init first launch detector"); + clientServiceLocator.getFirstLaunchDetector().init(mContext); DebugLogger.INSTANCE.info(TAG, "Check client migration"); new ClientMigrationManager(mContext).checkMigration(mContext); DebugLogger.INSTANCE.info(TAG, "Warm up uuid"); @@ -239,6 +242,7 @@ public void requestStartupParams( @NonNull final StartupParamsCallback callback, @NonNull final List params ) { + DebugLogger.INSTANCE.info(TAG, "requestStartupParams"); getImpl().requestStartupParams(callback, params); } diff --git a/analytics/src/main/java/io/appmetrica/analytics/impl/AppMetricaImpl.kt b/analytics/src/main/java/io/appmetrica/analytics/impl/AppMetricaImpl.kt index a9b63ae3..8b873a60 100644 --- a/analytics/src/main/java/io/appmetrica/analytics/impl/AppMetricaImpl.kt +++ b/analytics/src/main/java/io/appmetrica/analytics/impl/AppMetricaImpl.kt @@ -86,7 +86,7 @@ internal class AppMetricaImpl @WorkerThread internal constructor( startupHelper ) sessionsTrackingManager = clientServiceLocator.sessionsTrackingManager - anonymousConfigProvider = AppMetricaConfigForAnonymousActivationProvider(context, clientPreferences) + anonymousConfigProvider = AppMetricaConfigForAnonymousActivationProvider(clientPreferences) } @WorkerThread diff --git a/analytics/src/main/java/io/appmetrica/analytics/impl/ClientServiceLocator.java b/analytics/src/main/java/io/appmetrica/analytics/impl/ClientServiceLocator.java index f1a0e278..46286b29 100644 --- a/analytics/src/main/java/io/appmetrica/analytics/impl/ClientServiceLocator.java +++ b/analytics/src/main/java/io/appmetrica/analytics/impl/ClientServiceLocator.java @@ -14,6 +14,7 @@ import io.appmetrica.analytics.impl.reporter.ReporterLifecycleListener; import io.appmetrica.analytics.impl.startup.uuid.MultiProcessSafeUuidProvider; import io.appmetrica.analytics.impl.startup.uuid.UuidFromClientPreferencesImporter; +import io.appmetrica.analytics.impl.utils.FirstLaunchDetector; import io.appmetrica.analytics.impl.utils.MainProcessDetector; import io.appmetrica.analytics.impl.utils.ProcessDetector; import io.appmetrica.analytics.impl.utils.executors.ClientExecutorProvider; @@ -72,6 +73,8 @@ public static ClientServiceLocator getInstance() { private ScreenInfoRetriever screenInfoRetriever; @NonNull private final AppMetricaFacadeProvider appMetricaFacadeProvider = new AppMetricaFacadeProvider(); + @NonNull + private final FirstLaunchDetector firstLaunchDetector = new FirstLaunchDetector(); private ClientServiceLocator() { this(new MainProcessDetector(), new ActivityLifecycleManager(), new ClientExecutorProvider()); @@ -264,6 +267,11 @@ public AppMetricaFacadeProvider getAppMetricaFacadeProvider() { return appMetricaFacadeProvider; } + @NonNull + public FirstLaunchDetector getFirstLaunchDetector() { + return firstLaunchDetector; + } + @VisibleForTesting(otherwise = VisibleForTesting.NONE) public static void setInstance(@Nullable ClientServiceLocator clientServiceLocator) { sHolder = clientServiceLocator; diff --git a/analytics/src/main/java/io/appmetrica/analytics/impl/proxy/AppMetricaLibraryAdapterProxy.kt b/analytics/src/main/java/io/appmetrica/analytics/impl/proxy/AppMetricaLibraryAdapterProxy.kt index 6fc31e9c..8a5f105a 100644 --- a/analytics/src/main/java/io/appmetrica/analytics/impl/proxy/AppMetricaLibraryAdapterProxy.kt +++ b/analytics/src/main/java/io/appmetrica/analytics/impl/proxy/AppMetricaLibraryAdapterProxy.kt @@ -7,9 +7,12 @@ import io.appmetrica.analytics.impl.ClientServiceLocator import io.appmetrica.analytics.impl.events.LibraryEventConstructor import io.appmetrica.analytics.impl.proxy.synchronous.LibraryAdapterSynchronousStageExecutor import io.appmetrica.analytics.impl.proxy.validation.LibraryAdapterBarrier +import io.appmetrica.analytics.logger.appmetrica.internal.DebugLogger class AppMetricaLibraryAdapterProxy { + private val tag = "[AppMetricaLibraryAdapterProxy]" + private val provider: AppMetricaFacadeProvider = ClientServiceLocator.getInstance().appMetricaFacadeProvider private val barrier = LibraryAdapterBarrier(provider) @@ -19,10 +22,12 @@ class AppMetricaLibraryAdapterProxy { ClientServiceLocator.getInstance().clientExecutorProvider.defaultExecutor fun activate(context: Context) { + DebugLogger.info(tag, "Activate") barrier.activate(context) val applicationContext = context.applicationContext synchronousStageExecutor.activate(applicationContext) executor.execute { + DebugLogger.info(tag, "Activate full") provider.getInitializedImpl(applicationContext).activateFull() } provider.markActivated() diff --git a/analytics/src/main/java/io/appmetrica/analytics/impl/proxy/AppMetricaProxy.java b/analytics/src/main/java/io/appmetrica/analytics/impl/proxy/AppMetricaProxy.java index 309e50aa..fa115736 100644 --- a/analytics/src/main/java/io/appmetrica/analytics/impl/proxy/AppMetricaProxy.java +++ b/analytics/src/main/java/io/appmetrica/analytics/impl/proxy/AppMetricaProxy.java @@ -494,6 +494,7 @@ public void requestStartupParams( @NonNull final StartupParamsCallback callback, @NonNull final List params ) { + DebugLogger.INSTANCE.info(TAG, "requestStartupParams for keys: %s", params); barrier.requestStartupParams(context, callback, params); synchronousStageExecutor.requestStartupParams(context.getApplicationContext(), callback, params); getExecutor().execute(new Runnable() { diff --git a/analytics/src/main/java/io/appmetrica/analytics/impl/proxy/synchronous/SynchronousStageExecutor.kt b/analytics/src/main/java/io/appmetrica/analytics/impl/proxy/synchronous/SynchronousStageExecutor.kt index cb928ea1..6c838f92 100644 --- a/analytics/src/main/java/io/appmetrica/analytics/impl/proxy/synchronous/SynchronousStageExecutor.kt +++ b/analytics/src/main/java/io/appmetrica/analytics/impl/proxy/synchronous/SynchronousStageExecutor.kt @@ -30,6 +30,7 @@ import io.appmetrica.analytics.impl.WebViewJsInterfaceHandler import io.appmetrica.analytics.impl.crash.AppMetricaThrowable import io.appmetrica.analytics.impl.proxy.AppMetricaFacadeProvider import io.appmetrica.analytics.impl.proxy.AppMetricaProxy +import io.appmetrica.analytics.impl.utils.FirstLaunchDetector import io.appmetrica.analytics.profile.UserProfile class SynchronousStageExecutor @VisibleForTesting constructor( @@ -37,7 +38,8 @@ class SynchronousStageExecutor @VisibleForTesting constructor( private val webViewJsInterfaceHandler: WebViewJsInterfaceHandler, private val activityLifecycleManager: ActivityLifecycleManager, private val sessionsTrackingManager: SessionsTrackingManager, - private val contextAppearedListener: ContextAppearedListener + private val contextAppearedListener: ContextAppearedListener, + private val firstLaunchDetector: FirstLaunchDetector ) { constructor( @@ -48,7 +50,8 @@ class SynchronousStageExecutor @VisibleForTesting constructor( webViewJsInterfaceHandler, ClientServiceLocator.getInstance().activityLifecycleManager, ClientServiceLocator.getInstance().sessionsTrackingManager, - ClientServiceLocator.getInstance().contextAppearedListener + ClientServiceLocator.getInstance().contextAppearedListener, + ClientServiceLocator.getInstance().firstLaunchDetector ) fun putAppEnvironmentValue( @@ -196,6 +199,7 @@ class SynchronousStageExecutor @VisibleForTesting constructor( fun getUuid(context: Context) { contextAppearedListener.onProbablyAppeared(context) + firstLaunchDetector.init(context) } fun registerAnrListener(listener: AnrListener) {} diff --git a/analytics/src/main/java/io/appmetrica/analytics/impl/utils/FirstLaunchDetector.kt b/analytics/src/main/java/io/appmetrica/analytics/impl/utils/FirstLaunchDetector.kt index 05361b3b..eb682f09 100644 --- a/analytics/src/main/java/io/appmetrica/analytics/impl/utils/FirstLaunchDetector.kt +++ b/analytics/src/main/java/io/appmetrica/analytics/impl/utils/FirstLaunchDetector.kt @@ -9,7 +9,27 @@ class FirstLaunchDetector { private val tag = "[FirstLaunchDetector]" - fun detectNotFirstLaunch(context: Context): Boolean = try { + @Volatile + private var notAFirstLaunch: Boolean? = null + + fun init(context: Context) { + DebugLogger.info(tag, "init") + var localValue = notAFirstLaunch + if (localValue == null) { + synchronized(this) { + localValue = notAFirstLaunch + if (localValue == null) { + localValue = detectNotFirstLaunch(context) + DebugLogger.info(tag, "detected not a first launch value: $localValue") + notAFirstLaunch = localValue + } + } + } + } + + fun isNotFirstLaunch(): Boolean = notAFirstLaunch == true + + private fun detectNotFirstLaunch(context: Context): Boolean = try { val legacyExists = FileUtils.getFileFromAppStorage(context, FileConstants.UUID_FILE_NAME)?.exists() ?: false val actualExists = FileUtils.getFileFromSdkStorage(context, FileConstants.UUID_FILE_NAME)?.exists() ?: false legacyExists || actualExists diff --git a/analytics/src/test/java/io/appmetrica/analytics/impl/AppMetricaConfigForAnonymousActivationProviderTest.kt b/analytics/src/test/java/io/appmetrica/analytics/impl/AppMetricaConfigForAnonymousActivationProviderTest.kt index ebc17526..c30c90ad 100644 --- a/analytics/src/test/java/io/appmetrica/analytics/impl/AppMetricaConfigForAnonymousActivationProviderTest.kt +++ b/analytics/src/test/java/io/appmetrica/analytics/impl/AppMetricaConfigForAnonymousActivationProviderTest.kt @@ -14,7 +14,6 @@ import org.mockito.kotlin.whenever class AppMetricaConfigForAnonymousActivationProviderTest : CommonTest() { - private val context: Context = mock() private val configFromPreferences: AppMetricaConfig = mock() private val defaultConfig: AppMetricaConfig = mock() private val preferences: PreferencesClientDbStorage = mock() @@ -22,11 +21,11 @@ class AppMetricaConfigForAnonymousActivationProviderTest : CommonTest() { @get:Rule val defaultAnonymousConfigProviderMockedConstructionRule = constructionRule { - on { getConfig(context) } doReturn defaultConfig + on { getConfig() } doReturn defaultConfig } private val configProvider: AppMetricaConfigForAnonymousActivationProvider by setUp { - AppMetricaConfigForAnonymousActivationProvider(context, preferences) + AppMetricaConfigForAnonymousActivationProvider(preferences) } @Test diff --git a/analytics/src/test/java/io/appmetrica/analytics/impl/AppMetricaDefaultAnonymousConfigProviderTest.kt b/analytics/src/test/java/io/appmetrica/analytics/impl/AppMetricaDefaultAnonymousConfigProviderTest.kt index 06e0ebc4..17a14092 100644 --- a/analytics/src/test/java/io/appmetrica/analytics/impl/AppMetricaDefaultAnonymousConfigProviderTest.kt +++ b/analytics/src/test/java/io/appmetrica/analytics/impl/AppMetricaDefaultAnonymousConfigProviderTest.kt @@ -6,30 +6,20 @@ import io.appmetrica.analytics.impl.utils.FirstLaunchDetector import io.appmetrica.analytics.impl.utils.MainProcessDetector import io.appmetrica.analytics.testutils.ClientServiceLocatorRule import io.appmetrica.analytics.testutils.CommonTest -import io.appmetrica.analytics.testutils.constructionRule import org.assertj.core.api.Assertions.assertThat import org.junit.Before import org.junit.Rule import org.junit.Test import org.mockito.Mockito.mock -import org.mockito.kotlin.doReturn import org.mockito.kotlin.whenever class AppMetricaDefaultAnonymousConfigProviderTest : CommonTest() { - private val context: Context = mock() - @get:Rule val clientServiceLocatorRule = ClientServiceLocatorRule() private lateinit var mainProcessDetector: MainProcessDetector - - @get:Rule - val firstLaunchDetectorMockedConstructionRule = constructionRule { - on { detectNotFirstLaunch(context) } doReturn false - } - - private val firstLaunchDetector: FirstLaunchDetector by firstLaunchDetectorMockedConstructionRule + private lateinit var firstLaunchDetector: FirstLaunchDetector private val apiKey = "629a824d-c717-4ba5-bc0f-3f3968554d01" @@ -39,30 +29,31 @@ class AppMetricaDefaultAnonymousConfigProviderTest : CommonTest() { @Before fun setUp() { + firstLaunchDetector = ClientServiceLocator.getInstance().firstLaunchDetector mainProcessDetector = ClientServiceLocator.getInstance().mainProcessDetector whenever(mainProcessDetector.isMainProcess).thenReturn(true) } @Test fun getConfig() { - assertThat(appMetricaDefaultAnonymousConfigProvider.getConfig(context)) + assertThat(appMetricaDefaultAnonymousConfigProvider.getConfig()) .usingRecursiveComparison() .isEqualTo(AppMetricaConfig.newConfigBuilder(apiKey).build()) } @Test fun `getConfig for main process and not first launch`() { - whenever(firstLaunchDetector.detectNotFirstLaunch(context)).thenReturn(true) - assertThat(appMetricaDefaultAnonymousConfigProvider.getConfig(context)) + whenever(firstLaunchDetector.isNotFirstLaunch()).thenReturn(true) + assertThat(appMetricaDefaultAnonymousConfigProvider.getConfig()) .usingRecursiveComparison() .isEqualTo(AppMetricaConfig.newConfigBuilder(apiKey).handleFirstActivationAsUpdate(true).build()) } @Test fun `getConfig for non main process and not first launch`() { - whenever(firstLaunchDetector.detectNotFirstLaunch(context)).thenReturn(true) + whenever(firstLaunchDetector.isNotFirstLaunch()).thenReturn(true) whenever(mainProcessDetector.isMainProcess).thenReturn(false) - assertThat(appMetricaDefaultAnonymousConfigProvider.getConfig(context)) + assertThat(appMetricaDefaultAnonymousConfigProvider.getConfig()) .usingRecursiveComparison() .isEqualTo(AppMetricaConfig.newConfigBuilder(apiKey).build()) } diff --git a/analytics/src/test/java/io/appmetrica/analytics/impl/AppMetricaFacadeObjectTest.java b/analytics/src/test/java/io/appmetrica/analytics/impl/AppMetricaFacadeObjectTest.java index 598c14c6..8b372ed6 100644 --- a/analytics/src/test/java/io/appmetrica/analytics/impl/AppMetricaFacadeObjectTest.java +++ b/analytics/src/test/java/io/appmetrica/analytics/impl/AppMetricaFacadeObjectTest.java @@ -9,6 +9,8 @@ import io.appmetrica.analytics.StartupParamsCallback; import io.appmetrica.analytics.coreapi.internal.executors.IHandlerExecutor; import io.appmetrica.analytics.impl.startup.Constants; +import io.appmetrica.analytics.impl.startup.uuid.MultiProcessSafeUuidProvider; +import io.appmetrica.analytics.impl.utils.FirstLaunchDetector; import io.appmetrica.analytics.impl.utils.executors.ClientExecutorProvider; import io.appmetrica.analytics.testutils.ClientServiceLocatorRule; import io.appmetrica.analytics.testutils.CommonTest; @@ -23,12 +25,14 @@ import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Captor; +import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -104,7 +108,13 @@ public void futureIsNotInited() { assertThat(clientMigrationManagerMockedConstructionRule.getConstructionMock().constructed()).hasSize(1); assertThat(clientMigrationManagerMockedConstructionRule.getArgumentInterceptor().flatArguments()) .containsOnly(mContext); - verify(ClientServiceLocator.getInstance().getMultiProcessSafeUuidProvider(mContext), times(1)).readUuid(); + FirstLaunchDetector firstLaunchDetector = ClientServiceLocator.getInstance().getFirstLaunchDetector(); + MultiProcessSafeUuidProvider multiProcessSafeUuidProvider = + ClientServiceLocator.getInstance().getMultiProcessSafeUuidProvider(mContext); + InOrder inOrder = inOrder(firstLaunchDetector, multiProcessSafeUuidProvider); + inOrder.verify(firstLaunchDetector).init(mContext); + inOrder.verify(multiProcessSafeUuidProvider).readUuid(); + inOrder.verifyNoMoreInteractions(); } @Test diff --git a/analytics/src/test/java/io/appmetrica/analytics/impl/ClientServiceLocatorTest.java b/analytics/src/test/java/io/appmetrica/analytics/impl/ClientServiceLocatorTest.java index 98f3711e..f1fce2c9 100644 --- a/analytics/src/test/java/io/appmetrica/analytics/impl/ClientServiceLocatorTest.java +++ b/analytics/src/test/java/io/appmetrica/analytics/impl/ClientServiceLocatorTest.java @@ -12,6 +12,7 @@ import io.appmetrica.analytics.impl.reporter.ReporterLifecycleListener; import io.appmetrica.analytics.impl.startup.uuid.MultiProcessSafeUuidProvider; import io.appmetrica.analytics.impl.startup.uuid.UuidFromClientPreferencesImporter; +import io.appmetrica.analytics.impl.utils.FirstLaunchDetector; import io.appmetrica.analytics.impl.utils.MainProcessDetector; import io.appmetrica.analytics.impl.utils.executors.ClientExecutorProvider; import io.appmetrica.analytics.testutils.CommonTest; @@ -86,6 +87,10 @@ public class ClientServiceLocatorTest extends CommonTest { public MockedConstructionRule appMetricaFacadeProviderMockedConstructionRule = new MockedConstructionRule<>(AppMetricaFacadeProvider.class); + @Rule + public MockedConstructionRule firstLaunchDetectorMockedConstructionRule = + new MockedConstructionRule<>(FirstLaunchDetector.class); + @Mock private DatabaseStorageFactory databaseStorage; @Mock @@ -174,7 +179,7 @@ public void getMainReporterLifecycleListener() { public void allFieldsFilled() throws Exception { ObjectPropertyAssertions(mClientServiceLocator) .withDeclaredAccessibleFields(true) - .withIgnoredFields("moduleEntryPointsRegister", "appMetricaFacadeProvider") + .withIgnoredFields("moduleEntryPointsRegister", "appMetricaFacadeProvider", "firstLaunchDetector") .checkField("mainProcessDetector", "getMainProcessDetector", mMainProcessDetector) .checkField("defaultOneShotConfig", "getDefaultOneShotConfig", mDefaultOneShotMetricaConfig) .checkField("clientExecutorProvider", "getClientExecutorProvider", mClientExecutorProvider) @@ -247,4 +252,12 @@ public void getAppMetricaFacadeProvider() { assertThat(appMetricaFacadeProviderMockedConstructionRule.getConstructionMock().constructed()).hasSize(1); assertThat(appMetricaFacadeProviderMockedConstructionRule.getArgumentInterceptor().flatArguments()).isEmpty(); } + + @Test + public void getFirstLaunchDetector() { + assertThat(mClientServiceLocator.getFirstLaunchDetector()) + .isEqualTo(firstLaunchDetectorMockedConstructionRule.getConstructionMock().constructed().get(0)); + assertThat(firstLaunchDetectorMockedConstructionRule.getConstructionMock().constructed()).hasSize(1); + assertThat(firstLaunchDetectorMockedConstructionRule.getArgumentInterceptor().flatArguments()).isEmpty(); + } } diff --git a/analytics/src/test/java/io/appmetrica/analytics/impl/proxy/synchronous/SynchronousStageExecutorContextTest.kt b/analytics/src/test/java/io/appmetrica/analytics/impl/proxy/synchronous/SynchronousStageExecutorContextTest.kt index 85339a03..718d3277 100644 --- a/analytics/src/test/java/io/appmetrica/analytics/impl/proxy/synchronous/SynchronousStageExecutorContextTest.kt +++ b/analytics/src/test/java/io/appmetrica/analytics/impl/proxy/synchronous/SynchronousStageExecutorContextTest.kt @@ -10,6 +10,7 @@ import io.appmetrica.analytics.impl.ContextAppearedListener import io.appmetrica.analytics.impl.SessionsTrackingManager import io.appmetrica.analytics.impl.WebViewJsInterfaceHandler import io.appmetrica.analytics.impl.proxy.AppMetricaFacadeProvider +import io.appmetrica.analytics.impl.utils.FirstLaunchDetector import io.appmetrica.analytics.testutils.ClientServiceLocatorRule import io.appmetrica.analytics.testutils.CommonTest import io.appmetrica.analytics.testutils.ContextCoverageUtils @@ -35,13 +36,15 @@ class SynchronousStageExecutorContextTest : CommonTest() { private val sessionsTrackingManager: SessionsTrackingManager = mock() private val activityLifecycleManager: ActivityLifecycleManager = mock() private val contextAppearedListener: ContextAppearedListener = mock() + private val firstLaunchDetector: FirstLaunchDetector = mock() private val synchronousStageExecutor = SynchronousStageExecutor( provider, webViewJsInterfaceHandler, activityLifecycleManager, sessionsTrackingManager, - contextAppearedListener + contextAppearedListener, + firstLaunchDetector ) private val apiKey = UUID.randomUUID().toString() diff --git a/analytics/src/test/java/io/appmetrica/analytics/impl/proxy/synchronous/SynchronousStageExecutorTest.java b/analytics/src/test/java/io/appmetrica/analytics/impl/proxy/synchronous/SynchronousStageExecutorTest.java index 662ddd77..ce5adc74 100644 --- a/analytics/src/test/java/io/appmetrica/analytics/impl/proxy/synchronous/SynchronousStageExecutorTest.java +++ b/analytics/src/test/java/io/appmetrica/analytics/impl/proxy/synchronous/SynchronousStageExecutorTest.java @@ -15,6 +15,7 @@ import io.appmetrica.analytics.impl.crash.AppMetricaThrowable; import io.appmetrica.analytics.impl.proxy.AppMetricaFacadeProvider; import io.appmetrica.analytics.impl.proxy.AppMetricaProxy; +import io.appmetrica.analytics.impl.utils.FirstLaunchDetector; import io.appmetrica.analytics.logger.appmetrica.internal.PublicLogger; import io.appmetrica.analytics.testutils.ClientServiceLocatorRule; import io.appmetrica.analytics.testutils.CommonTest; @@ -55,6 +56,8 @@ public class SynchronousStageExecutorTest extends CommonTest { private ActivityLifecycleManager activityLifecycleManager; @Mock private ContextAppearedListener contextAppearedListener; + @Mock + private FirstLaunchDetector firstLaunchDetector; private SynchronousStageExecutor synchronousStageExecutor; private final String mEventName = "EVENT_NAME"; @@ -77,7 +80,8 @@ public void setUp() { webViewJsInterfaceHandler, activityLifecycleManager, sessionsTrackingManager, - contextAppearedListener + contextAppearedListener, + firstLaunchDetector ); } @@ -233,6 +237,7 @@ public void initWebViewReporting() { public void getUuid() { synchronousStageExecutor.getUuid(mContext); + verify(firstLaunchDetector).init(mContext); verify(contextAppearedListener).onProbablyAppeared(mContext); } } diff --git a/analytics/src/test/java/io/appmetrica/analytics/impl/utils/FirstLaunchDetectorTest.kt b/analytics/src/test/java/io/appmetrica/analytics/impl/utils/FirstLaunchDetectorTest.kt index 3a28edd2..774d6322 100644 --- a/analytics/src/test/java/io/appmetrica/analytics/impl/utils/FirstLaunchDetectorTest.kt +++ b/analytics/src/test/java/io/appmetrica/analytics/impl/utils/FirstLaunchDetectorTest.kt @@ -6,6 +6,7 @@ import io.appmetrica.analytics.impl.db.FileConstants import io.appmetrica.analytics.testutils.CommonTest import io.appmetrica.analytics.testutils.staticRule import org.assertj.core.api.Assertions.assertThat +import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith @@ -47,8 +48,8 @@ class FirstLaunchDetectorTest( private val firstLaunchDetector: FirstLaunchDetector by setUp { FirstLaunchDetector() } - @Test - fun detectNotFirstLaunch() { + @Before + fun setUp() { if (uuidFileExists != null) { whenever(actualFile.exists()).thenReturn(uuidFileExists) whenever(FileUtils.getFileFromSdkStorage(context, FileConstants.UUID_FILE_NAME)).thenReturn(actualFile) @@ -57,7 +58,21 @@ class FirstLaunchDetectorTest( whenever(legacyFile.exists()).thenReturn(legacyUuidFileExists) whenever(FileUtils.getFileFromAppStorage(context, FileConstants.UUID_FILE_NAME)).thenReturn(legacyFile) } + } + + @Test + fun isNotFirstLaunch() { + // Before init + assertThat(firstLaunchDetector.isNotFirstLaunch()).isEqualTo(false) + + // Init + firstLaunchDetector.init(context) + assertThat(firstLaunchDetector.isNotFirstLaunch()).isEqualTo(expectedValue) - assertThat(firstLaunchDetector.detectNotFirstLaunch(context)).isEqualTo(expectedValue) + // Second init + whenever(FileUtils.getFileFromSdkStorage(context, FileConstants.UUID_FILE_NAME)).thenReturn(null) + whenever(FileUtils.getFileFromAppStorage(context, FileConstants.UUID_FILE_NAME)).thenReturn(null) + firstLaunchDetector.init(context) + assertThat(firstLaunchDetector.isNotFirstLaunch()).isEqualTo(expectedValue) } } diff --git a/analytics/src/test/java/io/appmetrica/analytics/testutils/ClientServiceLocatorRule.java b/analytics/src/test/java/io/appmetrica/analytics/testutils/ClientServiceLocatorRule.java index 19393991..5518f2b3 100644 --- a/analytics/src/test/java/io/appmetrica/analytics/testutils/ClientServiceLocatorRule.java +++ b/analytics/src/test/java/io/appmetrica/analytics/testutils/ClientServiceLocatorRule.java @@ -17,6 +17,7 @@ import io.appmetrica.analytics.impl.modules.client.ClientModulesController; import io.appmetrica.analytics.impl.proxy.AppMetricaFacadeProvider; import io.appmetrica.analytics.impl.startup.uuid.MultiProcessSafeUuidProvider; +import io.appmetrica.analytics.impl.utils.FirstLaunchDetector; import io.appmetrica.analytics.impl.utils.MainProcessDetector; import io.appmetrica.analytics.impl.utils.ProcessDetector; import io.appmetrica.analytics.impl.utils.executors.ClientExecutorProvider; @@ -47,6 +48,7 @@ public class ClientServiceLocatorRule extends ExternalResource { public PreferencesClientDbStorage preferencesClientDbStorage; public AppMetricaFacadeProvider appMetricaFacadeProvider; public AppMetricaCoreComponentsProvider appMetricaCoreComponentsProvider; + public FirstLaunchDetector firstLaunchDetector; public ClientServiceLocator instance; @Override @@ -70,6 +72,7 @@ public void before() { preferencesClientDbStorage = mock(PreferencesClientDbStorage.class); appMetricaFacadeProvider = mock(AppMetricaFacadeProvider.class); appMetricaCoreComponentsProvider = mock(AppMetricaCoreComponentsProvider.class); + firstLaunchDetector = mock(FirstLaunchDetector.class); when(instance.getClientExecutorProvider()).thenReturn(clientExecutorProvider); when(instance.getDefaultOneShotConfig()).thenReturn(mDefaultOneShotMetricaConfig); when(instance.getMainProcessDetector()).thenReturn(mainProcessDetector); @@ -92,6 +95,7 @@ public void before() { when(clientExecutorProvider.getReportSenderExecutor()).thenReturn(new StubbedBlockingExecutor()); Handler mainHandler = TestUtils.createBlockingExecutionHandlerStub(); when(clientExecutorProvider.getMainHandler()).thenReturn(mainHandler); + when(instance.getFirstLaunchDetector()).thenReturn(firstLaunchDetector); ClientServiceLocator.setInstance(instance); }