Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import androidx.test.platform.app.InstrumentationRegistry
import androidx.work.WorkInfo
import androidx.work.WorkManager
import com.duckduckgo.app.CoroutineTestRule
import com.duckduckgo.app.notification.AndroidNotificationScheduler.*
import com.duckduckgo.app.notification.NotificationScheduler.*
import com.duckduckgo.app.notification.model.SchedulableNotification
import com.duckduckgo.app.notification.model.SearchNotification
import com.duckduckgo.app.statistics.VariantManager
Expand All @@ -39,7 +39,7 @@ import org.junit.Rule
import org.junit.Test
import kotlin.reflect.jvm.jvmName

class NotificationSchedulerTest {
class AndroidNotificationSchedulerTest {

@ExperimentalCoroutinesApi
@get:Rule
Expand All @@ -57,7 +57,7 @@ class NotificationSchedulerTest {
@Before
fun before() {
whenever(variantManager.getVariant(any())).thenReturn(DEFAULT_VARIANT)
testee = AndroidNotificationScheduler(
testee = NotificationScheduler(
workManager,
clearNotification,
privacyNotification,
Expand All @@ -67,7 +67,7 @@ class NotificationSchedulerTest {

@After
fun resetWorkers() {
workManager.cancelAllWorkByTag(AndroidNotificationScheduler.CONTINUOUS_APP_USE_REQUEST_TAG)
workManager.cancelAllWorkByTag(NotificationScheduler.CONTINUOUS_APP_USE_REQUEST_TAG)
}

@Test
Expand Down Expand Up @@ -141,6 +141,7 @@ class NotificationSchedulerTest {
whenever(privacyNotification.canShow()).thenReturn(false)
whenever(clearNotification.canShow()).thenReturn(false)
whenever(searchPromptNotification.canShow()).thenReturn(true)

testee.scheduleNextNotification()

assertContinuousAppUseNotificationScheduled(SearchPromptNotificationWorker::class.jvmName)
Expand Down Expand Up @@ -180,14 +181,14 @@ class NotificationSchedulerTest {

private fun getUnusedAppScheduledWorkers(): List<WorkInfo> {
return workManager
.getWorkInfosByTag(AndroidNotificationScheduler.UNUSED_APP_WORK_REQUEST_TAG)
.getWorkInfosByTag(NotificationScheduler.UNUSED_APP_WORK_REQUEST_TAG)
.get()
.filter { it.state == WorkInfo.State.ENQUEUED }
}

private fun getContinuousAppUseScheduledWorkers(): List<WorkInfo> {
return workManager
.getWorkInfosByTag(AndroidNotificationScheduler.CONTINUOUS_APP_USE_REQUEST_TAG)
.getWorkInfosByTag(NotificationScheduler.CONTINUOUS_APP_USE_REQUEST_TAG)
.get()
.filter { it.state == WorkInfo.State.ENQUEUED }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import com.duckduckgo.app.browser.BuildConfig
import com.duckduckgo.app.browser.defaultbrowsing.DefaultBrowserDetector
import com.duckduckgo.app.global.DuckDuckGoTheme
import com.duckduckgo.app.icon.api.AppIcon
import com.duckduckgo.app.notification.NotificationScheduler
import com.duckduckgo.app.notification.AndroidNotificationScheduler
import com.duckduckgo.app.settings.SettingsViewModel.Command
import com.duckduckgo.app.settings.clear.ClearWhatOption.CLEAR_NONE
import com.duckduckgo.app.settings.clear.ClearWhenOption.APP_EXIT_ONLY
Expand Down Expand Up @@ -68,7 +68,7 @@ class SettingsViewModelTest {
private lateinit var mockVariantManager: VariantManager

@Mock
private lateinit var notificationScheduler: NotificationScheduler
private lateinit var notificationScheduler: AndroidNotificationScheduler

@Mock
private lateinit var mockPixel: Pixel
Expand Down
38 changes: 24 additions & 14 deletions app/src/main/java/com/duckduckgo/app/di/DaggerWorkerFactory.kt
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@ import androidx.work.WorkerFactory
import androidx.work.WorkerParameters
import com.duckduckgo.app.fire.DataClearingWorker
import com.duckduckgo.app.global.view.ClearDataAction
import com.duckduckgo.app.notification.AndroidNotificationScheduler.*
import com.duckduckgo.app.notification.NotificationScheduler.ClearDataNotificationWorker
import com.duckduckgo.app.notification.NotificationScheduler.PrivacyNotificationWorker
import com.duckduckgo.app.notification.NotificationScheduler.SearchPromptNotificationWorker
import com.duckduckgo.app.notification.NotificationScheduler.StickySearchNotificationWorker
import com.duckduckgo.app.notification.NotificationScheduler.DismissSearchNotificationWorker
import com.duckduckgo.app.notification.NotificationFactory
import com.duckduckgo.app.notification.db.NotificationDao
import com.duckduckgo.app.notification.model.ClearDataNotification
Expand Down Expand Up @@ -52,22 +56,28 @@ class DaggerWorkerFactory(

override fun createWorker(appContext: Context, workerClassName: String, workerParameters: WorkerParameters): ListenableWorker? {

val workerClass = Class.forName(workerClassName).asSubclass(ListenableWorker::class.java)
val constructor = workerClass.getDeclaredConstructor(Context::class.java, WorkerParameters::class.java)
val instance = constructor.newInstance(appContext, workerParameters)
try {
val workerClass = Class.forName(workerClassName).asSubclass(ListenableWorker::class.java)
val constructor = workerClass.getDeclaredConstructor(Context::class.java, WorkerParameters::class.java)
val instance = constructor.newInstance(appContext, workerParameters)

when (instance) {
is OfflinePixelScheduler.OfflinePixelWorker -> injectOfflinePixelWorker(instance)
is DataClearingWorker -> injectDataClearWorker(instance)
is ClearDataNotificationWorker -> injectClearDataNotificationWorker(instance)
is PrivacyNotificationWorker -> injectPrivacyNotificationWorker(instance)
is SearchPromptNotificationWorker -> injectSearchPromptNotificationWorker(instance)
is StickySearchNotificationWorker -> injectStickySearchNotificationWorker(instance)
is DismissSearchNotificationWorker -> injectDismissSearchNotificationWorker(instance)
else -> Timber.i("No injection required for worker $workerClassName")
when (instance) {
is OfflinePixelScheduler.OfflinePixelWorker -> injectOfflinePixelWorker(instance)
is DataClearingWorker -> injectDataClearWorker(instance)
is ClearDataNotificationWorker -> injectClearDataNotificationWorker(instance)
is PrivacyNotificationWorker -> injectPrivacyNotificationWorker(instance)
is SearchPromptNotificationWorker -> injectSearchPromptNotificationWorker(instance)
is StickySearchNotificationWorker -> injectStickySearchNotificationWorker(instance)
is DismissSearchNotificationWorker -> injectDismissSearchNotificationWorker(instance)
else -> Timber.i("No injection required for worker $workerClassName")
}

return instance
} catch (exception: Exception){
Timber.e(exception, "Worker $workerClassName could not be created")
return null
}

return instance
}

private fun injectOfflinePixelWorker(worker: OfflinePixelScheduler.OfflinePixelWorker) {
Expand Down
8 changes: 4 additions & 4 deletions app/src/main/java/com/duckduckgo/app/di/NotificationModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ import android.content.Context
import androidx.core.app.NotificationManagerCompat
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import androidx.work.WorkManager
import com.duckduckgo.app.notification.AndroidNotificationScheduler
import com.duckduckgo.app.notification.NotificationFactory
import com.duckduckgo.app.notification.NotificationScheduler
import com.duckduckgo.app.notification.NotificationFactory
import com.duckduckgo.app.notification.AndroidNotificationScheduler
import com.duckduckgo.app.notification.db.NotificationDao
import com.duckduckgo.app.notification.model.ClearDataNotification
import com.duckduckgo.app.notification.model.PrivacyProtectionNotification
Expand Down Expand Up @@ -100,8 +100,8 @@ class NotificationModule {
clearDataNotification: ClearDataNotification,
privacyProtectionNotification: PrivacyProtectionNotification,
stickySearchNotification: StickySearchNotification
): NotificationScheduler {
return AndroidNotificationScheduler(
): AndroidNotificationScheduler {
return NotificationScheduler(
workManager,
clearDataNotification,
privacyProtectionNotification,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ import com.duckduckgo.app.global.shortcut.AppShortcutCreator
import com.duckduckgo.app.httpsupgrade.HttpsUpgrader
import com.duckduckgo.app.job.AppConfigurationSyncer
import com.duckduckgo.app.notification.NotificationRegistrar
import com.duckduckgo.app.notification.NotificationScheduler
import com.duckduckgo.app.notification.AndroidNotificationScheduler
import com.duckduckgo.app.referral.AppInstallationReferrerStateListener
import com.duckduckgo.app.settings.db.SettingsDataStore
import com.duckduckgo.app.statistics.AtbInitializer
Expand Down Expand Up @@ -129,7 +129,7 @@ open class DuckDuckGoApplication : HasActivityInjector, HasServiceInjector, HasS
lateinit var dataClearer: DataClearer

@Inject
lateinit var notificationScheduler: NotificationScheduler
lateinit var notificationScheduler: AndroidNotificationScheduler

@Inject
lateinit var workerFactory: WorkerFactory
Expand Down
7 changes: 5 additions & 2 deletions app/src/main/java/com/duckduckgo/app/global/Theming.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import com.duckduckgo.app.browser.R
import com.duckduckgo.app.global.Theming.Constants.BROADCAST_THEME_CHANGED
import com.duckduckgo.app.global.Theming.Constants.THEME_MAP
import com.duckduckgo.app.settings.db.SettingsDataStore
import com.duckduckgo.app.statistics.VariantManager

enum class DuckDuckGoTheme {
DARK,
Expand Down Expand Up @@ -74,5 +73,9 @@ fun DuckDuckGoActivity.sendThemeChangedBroadcast() {
}

private fun DuckDuckGoActivity.manifestThemeId(): Int {
return packageManager.getActivityInfo(componentName, 0).themeResource
return try {
packageManager.getActivityInfo(componentName, 0).themeResource
} catch (exception: Exception) {
R.style.AppTheme
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,10 @@ import com.duckduckgo.app.global.install.AppInstallStore
import com.duckduckgo.app.global.model.SiteFactory
import com.duckduckgo.app.global.rating.AppEnjoymentPromptEmitter
import com.duckduckgo.app.global.rating.AppEnjoymentUserEventRecorder
import com.duckduckgo.app.icon.api.AppIconModifier
import com.duckduckgo.app.icon.api.IconModifier
import com.duckduckgo.app.icon.ui.ChangeIconViewModel
import com.duckduckgo.app.launch.LaunchViewModel
import com.duckduckgo.app.notification.NotificationScheduler
import com.duckduckgo.app.notification.AndroidNotificationScheduler
import com.duckduckgo.app.onboarding.store.OnboardingStore
import com.duckduckgo.app.onboarding.ui.OnboardingPageManager
import com.duckduckgo.app.onboarding.ui.OnboardingViewModel
Expand Down Expand Up @@ -112,7 +111,7 @@ class ViewModelFactory @Inject constructor(
private val onboardingPageManager: OnboardingPageManager,
private val appInstallationReferrerStateListener: AppInstallationReferrerStateListener,
private val appIconModifier: IconModifier,
private val notificationScheduler: NotificationScheduler
private val notificationScheduler: AndroidNotificationScheduler
) : ViewModelProvider.NewInstanceFactory() {

override fun <T : ViewModel> create(modelClass: Class<T>) =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,42 +17,39 @@
package com.duckduckgo.app.notification

import android.content.Context
import android.content.Intent
import androidx.annotation.WorkerThread
import androidx.core.app.NotificationManagerCompat
import androidx.work.CoroutineWorker
import androidx.work.OneTimeWorkRequest
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkManager
import androidx.work.WorkerParameters
import com.duckduckgo.app.notification.NotificationHandlerService.Companion.NOTIFICATION_AUTO_CANCEL
import com.duckduckgo.app.notification.NotificationHandlerService.Companion.NOTIFICATION_SYSTEM_ID_EXTRA
import com.duckduckgo.app.notification.NotificationHandlerService.Companion.PIXEL_SUFFIX_EXTRA
import com.duckduckgo.app.notification.db.NotificationDao
import com.duckduckgo.app.notification.model.Notification
import com.duckduckgo.app.notification.model.SchedulableNotification
import com.duckduckgo.app.notification.model.SearchNotification
import com.duckduckgo.app.notification.model.SearchPromptNotification
import com.duckduckgo.app.settings.db.SettingsDataStore
import com.duckduckgo.app.statistics.pixels.Pixel
import com.duckduckgo.app.statistics.pixels.Pixel.PixelName.NOTIFICATION_SHOWN
import timber.log.Timber
import java.util.concurrent.TimeUnit


// Please don't rename any Worker class name or class path
// More information: https://craigrussell.io/2019/04/a-workmanager-pitfall-modifying-a-scheduled-worker/
@WorkerThread
interface NotificationScheduler {
interface AndroidNotificationScheduler {
suspend fun scheduleNextNotification()
fun launchStickySearchNotification()
fun dismissStickySearchNotification()
fun launchSearchPromptNotification()
}

class AndroidNotificationScheduler(
class NotificationScheduler(
private val workManager: WorkManager,
private val clearDataNotification: SchedulableNotification,
private val privacyNotification: SchedulableNotification,
private val searchPromptNotification: SearchNotification
) : NotificationScheduler {
) : AndroidNotificationScheduler {

override suspend fun scheduleNextNotification() {
scheduleInactiveUserNotifications()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class NotificationHandlerService : IntentService("NotificationHandlerService") {
lateinit var notificationManager: NotificationManagerCompat

@Inject
lateinit var notificationScheduler: NotificationScheduler
lateinit var notificationScheduler: AndroidNotificationScheduler

@Inject
lateinit var settingsDataStore: SettingsDataStore
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import com.duckduckgo.app.browser.defaultbrowsing.DefaultBrowserDetector
import com.duckduckgo.app.global.DuckDuckGoTheme
import com.duckduckgo.app.global.SingleLiveEvent
import com.duckduckgo.app.icon.api.AppIcon
import com.duckduckgo.app.notification.NotificationScheduler
import com.duckduckgo.app.notification.AndroidNotificationScheduler
import com.duckduckgo.app.settings.clear.ClearWhatOption
import com.duckduckgo.app.settings.clear.ClearWhenOption
import com.duckduckgo.app.settings.db.SettingsDataStore
Expand All @@ -40,7 +40,7 @@ class SettingsViewModel @Inject constructor(
private val defaultWebBrowserCapability: DefaultBrowserDetector,
private val variantManager: VariantManager,
private val pixel: Pixel,
private val notificationScheduler: NotificationScheduler
private val notificationScheduler: AndroidNotificationScheduler
) : ViewModel() {

data class ViewState(
Expand Down