Skip to content

Commit

Permalink
Ensure InstallSource extraction logic runs after privacy config downl…
Browse files Browse the repository at this point in the history
…oaded (#5013)

Task/Issue URL: https://app.asana.com/0/608920331025315/1208315780180365/f 

### Description
Ensures install source extraction logic runs after privacy config has been downloaded. 
- This is needed by a higher level branch on the stack where remote config is read and used in the install source extraction. 
- This PR just lays the groundwork to support that use case

### Steps to test this PR

- [x] Fresh install
- [x] Run the app, and wait for privacy config to finish downloading
- [x] Verify you see `Installation source extracted` in the logs
- [x] Kill the app and re-open it, and wait for privacy config to finish
- [x] Verify you see `Already processed` in the logs
  • Loading branch information
CDRussell authored Sep 30, 2024
1 parent 125fcf0 commit 669d0b4
Show file tree
Hide file tree
Showing 2 changed files with 11 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,44 +16,43 @@

package com.duckduckgo.installation.impl.installer

import android.annotation.SuppressLint
import android.content.Context
import android.content.SharedPreferences
import androidx.annotation.VisibleForTesting
import androidx.core.content.edit
import androidx.lifecycle.LifecycleOwner
import com.duckduckgo.app.di.AppCoroutineScope
import com.duckduckgo.app.lifecycle.MainProcessLifecycleObserver
import com.duckduckgo.app.statistics.pixels.Pixel
import com.duckduckgo.common.utils.DispatcherProvider
import com.duckduckgo.di.scopes.AppScope
import com.duckduckgo.installation.impl.installer.InstallationPixelName.APP_INSTALLER_PACKAGE_NAME
import com.duckduckgo.privacy.config.api.PrivacyConfigCallbackPlugin
import com.squareup.anvil.annotations.ContributesMultibinding
import dagger.SingleInstanceIn
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import timber.log.Timber

@SuppressLint("DenyListedApi")
@ContributesMultibinding(
scope = AppScope::class,
boundType = MainProcessLifecycleObserver::class,
boundType = PrivacyConfigCallbackPlugin::class,
)
@SingleInstanceIn(AppScope::class)
class InstallSourceLifecycleObserver @Inject constructor(
class InstallSourcePrivacyConfigObserver @Inject constructor(
private val installSourceExtractor: InstallSourceExtractor,
private val context: Context,
private val pixel: Pixel,
private val dispatchers: DispatcherProvider,
@AppCoroutineScope private val appCoroutineScope: CoroutineScope,
) : MainProcessLifecycleObserver {
) : PrivacyConfigCallbackPlugin {

private val sharedPreferences: SharedPreferences by lazy {
context.getSharedPreferences(SHARED_PREFERENCES_FILENAME, Context.MODE_PRIVATE)
}

override fun onCreate(owner: LifecycleOwner) {
super.onCreate(owner)

override fun onPrivacyConfigDownloaded() {
appCoroutineScope.launch(dispatchers.io()) {
if (!hasAlreadyProcessed()) {
val installationSource = installSourceExtractor.extract()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

package com.duckduckgo.installation.impl.installer

import androidx.lifecycle.LifecycleOwner
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.duckduckgo.app.statistics.pixels.Pixel
import com.duckduckgo.app.statistics.pixels.Pixel.PixelType.Count
Expand All @@ -34,17 +33,16 @@ import org.mockito.kotlin.verify
import org.robolectric.RuntimeEnvironment

@RunWith(AndroidJUnit4::class)
class InstallSourceLifecycleObserverTest {
class InstallSourcePrivacyConfigObserverTest {

@get:Rule
val coroutineTestRule: CoroutineTestRule = CoroutineTestRule()

private val mockLifecycleOwner = mock<LifecycleOwner>()
private val mockPixel = mock<Pixel>()
private val context = RuntimeEnvironment.getApplication()
private val mockInstallSourceExtractor = mock<InstallSourceExtractor>()

private val testee = InstallSourceLifecycleObserver(
private val testee = InstallSourcePrivacyConfigObserver(
context = context,
pixel = mockPixel,
dispatchers = coroutineTestRule.testDispatcherProvider,
Expand All @@ -54,14 +52,14 @@ class InstallSourceLifecycleObserverTest {

@Test
fun whenNotPreviouslyProcessedThenPixelSent() = runTest {
testee.onCreate(mockLifecycleOwner)
testee.onPrivacyConfigDownloaded()
verify(mockPixel).fire(eq(APP_INSTALLER_PACKAGE_NAME), any(), any(), eq(Count))
}

@Test
fun whenPreviouslyProcessedThenPixelNotSent() = runTest {
testee.recordInstallSourceProcessed()
testee.onCreate(mockLifecycleOwner)
testee.onPrivacyConfigDownloaded()
verify(mockPixel, never()).fire(eq(APP_INSTALLER_PACKAGE_NAME), any(), any(), eq(Count))
}
}

0 comments on commit 669d0b4

Please sign in to comment.