Move NotificationsInteractor & related repos to shared.
We need a way to access notifications-related secure settings in new
sysui recommended architecture code. WallpaperPicker already had code
for this (in the form of a NotificationsInteractor,
NotificationsRepository and SecureSettingsRepository), so instead of
having multiple sources of truth for the same type of data, I moved
these to the shared package so both SystemUI and WallpaperPicker can
access them (see other CLs in topic).
I also renamed NotificationsInteractor and NotificationsRepository to
NotificationsSettingsInteractor and NotificationSettingsRepository
respectively, to better reflect the kind of data they handle.
This move also includes a very small behavior change - there was a
circular dependency between Notifications[Settings]Interactor and
NotificationsSnapshotRestorer, which deals with restoring setting when
the "Reset" button is pressed in WallpaperPicker. Since the snapshot
restorer only needs to exist in WallpaperPicker code, I split it from
the interactor and made it collect the settings flow from the interactor
directly.
I tested that this works correctly by running WallpaperPickerGoogle and
doing the following steps:
- open Lock screen customization page
- toggle "Show notifications on the lockscreen"
- lock the device to verify that the correct setting is applied
- unlock the device and press "Reset"
- verify that the toggle state is updated
- lock the device to verify that the old setting is applied
Keeping the test file in this package for now, because moving it is
complicated. See b/315806189.
Bug: 293167744
Test: manual (see steps above) + atest NotificationSettingsRepositoryTest
Flag: NONE
Change-Id: Iea3711af1871bb66ffed6f01c3fb1490d441cf02
diff --git a/src/com/android/customization/module/ThemePickerInjector.kt b/src/com/android/customization/module/ThemePickerInjector.kt
index f22e562..ffe3817 100644
--- a/src/com/android/customization/module/ThemePickerInjector.kt
+++ b/src/com/android/customization/module/ThemePickerInjector.kt
@@ -56,8 +56,6 @@
import com.android.customization.picker.grid.domain.interactor.GridInteractor
import com.android.customization.picker.grid.domain.interactor.GridSnapshotRestorer
import com.android.customization.picker.grid.ui.viewmodel.GridScreenViewModel
-import com.android.customization.picker.notifications.data.repository.NotificationsRepository
-import com.android.customization.picker.notifications.domain.interactor.NotificationsInteractor
import com.android.customization.picker.notifications.domain.interactor.NotificationsSnapshotRestorer
import com.android.customization.picker.notifications.ui.viewmodel.NotificationSectionViewModel
import com.android.customization.picker.quickaffordance.data.repository.KeyguardQuickAffordancePickerRepository
@@ -67,6 +65,8 @@
import com.android.systemui.shared.clocks.ClockRegistry
import com.android.systemui.shared.customization.data.content.CustomizationProviderClient
import com.android.systemui.shared.customization.data.content.CustomizationProviderClientImpl
+import com.android.systemui.shared.notifications.data.repository.NotificationSettingsRepository
+import com.android.systemui.shared.notifications.domain.interactor.NotificationSettingsInteractor
import com.android.wallpaper.config.BaseFlags
import com.android.wallpaper.module.CustomizationSections
import com.android.wallpaper.module.FragmentFactory
@@ -91,6 +91,7 @@
internal constructor(
@MainDispatcher private val mainScope: CoroutineScope,
@MainDispatcher private val mainDispatcher: CoroutineDispatcher,
+ @BackgroundDispatcher private val bgScope: CoroutineScope,
@BackgroundDispatcher private val bgDispatcher: CoroutineDispatcher,
private val userEventLogger: ThemesUserEventLogger,
) : WallpaperPicker2Injector(mainScope, bgDispatcher, userEventLogger), CustomizationInjector {
@@ -110,7 +111,7 @@
private var clockCarouselViewModelFactory: ClockCarouselViewModel.Factory? = null
private var clockViewFactory: ClockViewFactory? = null
private var clockPickerSnapshotRestorer: ClockPickerSnapshotRestorer? = null
- private var notificationsInteractor: NotificationsInteractor? = null
+ private var notificationSettingsInteractor: NotificationSettingsInteractor? = null
private var notificationSectionViewModelFactory: NotificationSectionViewModel.Factory? = null
private var colorPickerInteractor: ColorPickerInteractor? = null
private var colorPickerViewModelFactory: ColorPickerViewModel.Factory? = null
@@ -297,19 +298,17 @@
private fun getNotificationsInteractor(
context: Context,
- ): NotificationsInteractor {
- val appContext = context.applicationContext
- return notificationsInteractor
- ?: NotificationsInteractor(
+ ): NotificationSettingsInteractor {
+ return notificationSettingsInteractor
+ ?: NotificationSettingsInteractor(
repository =
- NotificationsRepository(
+ NotificationSettingsRepository(
scope = getApplicationCoroutineScope(),
backgroundDispatcher = bgDispatcher,
secureSettingsRepository = getSecureSettingsRepository(context),
),
- snapshotRestorer = { getNotificationsSnapshotRestorer(appContext) },
)
- .also { notificationsInteractor = it }
+ .also { notificationSettingsInteractor = it }
}
private fun getNotificationsSnapshotRestorer(context: Context): NotificationsSnapshotRestorer {
@@ -319,6 +318,7 @@
getNotificationsInteractor(
context = context,
),
+ backgroundScope = bgScope,
)
.also { notificationsSnapshotRestorer = it }
}
diff --git a/src/com/android/customization/picker/clock/data/repository/ClockPickerRepositoryImpl.kt b/src/com/android/customization/picker/clock/data/repository/ClockPickerRepositoryImpl.kt
index cc4079a..e329bc9 100644
--- a/src/com/android/customization/picker/clock/data/repository/ClockPickerRepositoryImpl.kt
+++ b/src/com/android/customization/picker/clock/data/repository/ClockPickerRepositoryImpl.kt
@@ -23,7 +23,7 @@
import com.android.customization.picker.clock.shared.model.ClockMetadataModel
import com.android.systemui.plugins.clocks.ClockMetadata
import com.android.systemui.shared.clocks.ClockRegistry
-import com.android.wallpaper.settings.data.repository.SecureSettingsRepository
+import com.android.systemui.shared.settings.data.repository.SecureSettingsRepository
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
diff --git a/src/com/android/customization/picker/notifications/data/repository/NotificationsRepository.kt b/src/com/android/customization/picker/notifications/data/repository/NotificationsRepository.kt
deleted file mode 100644
index c75ddce..0000000
--- a/src/com/android/customization/picker/notifications/data/repository/NotificationsRepository.kt
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package com.android.customization.picker.notifications.data.repository
-
-import android.provider.Settings
-import com.android.customization.picker.notifications.shared.model.NotificationSettingsModel
-import com.android.wallpaper.settings.data.repository.SecureSettingsRepository
-import kotlinx.coroutines.CoroutineDispatcher
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.flow.SharedFlow
-import kotlinx.coroutines.flow.SharingStarted
-import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.shareIn
-import kotlinx.coroutines.withContext
-
-/** Provides access to state related to notifications. */
-class NotificationsRepository(
- scope: CoroutineScope,
- private val backgroundDispatcher: CoroutineDispatcher,
- private val secureSettingsRepository: SecureSettingsRepository,
-) {
- /** The current state of the notification setting. */
- val settings: SharedFlow<NotificationSettingsModel> =
- secureSettingsRepository
- .intSetting(
- name = Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
- )
- .map { lockScreenShowNotificationsInt ->
- NotificationSettingsModel(
- isShowNotificationsOnLockScreenEnabled = lockScreenShowNotificationsInt == 1,
- )
- }
- .shareIn(
- scope = scope,
- started = SharingStarted.WhileSubscribed(),
- replay = 1,
- )
-
- suspend fun getSettings(): NotificationSettingsModel {
- return withContext(backgroundDispatcher) {
- NotificationSettingsModel(
- isShowNotificationsOnLockScreenEnabled =
- secureSettingsRepository.get(
- name = Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
- defaultValue = 0,
- ) == 1
- )
- }
- }
-
- suspend fun setSettings(model: NotificationSettingsModel) {
- withContext(backgroundDispatcher) {
- secureSettingsRepository.set(
- name = Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
- value = if (model.isShowNotificationsOnLockScreenEnabled) 1 else 0,
- )
- }
- }
-}
diff --git a/src/com/android/customization/picker/notifications/domain/interactor/NotificationsInteractor.kt b/src/com/android/customization/picker/notifications/domain/interactor/NotificationsInteractor.kt
deleted file mode 100644
index 1f892f0..0000000
--- a/src/com/android/customization/picker/notifications/domain/interactor/NotificationsInteractor.kt
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package com.android.customization.picker.notifications.domain.interactor
-
-import com.android.customization.picker.notifications.data.repository.NotificationsRepository
-import com.android.customization.picker.notifications.shared.model.NotificationSettingsModel
-import javax.inject.Provider
-import kotlinx.coroutines.flow.Flow
-
-/** Encapsulates business logic for interacting with notifications. */
-class NotificationsInteractor(
- private val repository: NotificationsRepository,
- private val snapshotRestorer: Provider<NotificationsSnapshotRestorer>,
-) {
- /** The current state of the notification setting. */
- val settings: Flow<NotificationSettingsModel> = repository.settings
-
- /** Toggles the setting to show or hide notifications on the lock screen. */
- suspend fun toggleShowNotificationsOnLockScreenEnabled() {
- val currentModel = repository.getSettings()
- setSettings(
- currentModel.copy(
- isShowNotificationsOnLockScreenEnabled =
- !currentModel.isShowNotificationsOnLockScreenEnabled,
- )
- )
- }
-
- suspend fun setSettings(model: NotificationSettingsModel) {
- repository.setSettings(model)
- snapshotRestorer.get().storeSnapshot(model)
- }
-
- suspend fun getSettings(): NotificationSettingsModel {
- return repository.getSettings()
- }
-}
diff --git a/src/com/android/customization/picker/notifications/domain/interactor/NotificationsSnapshotRestorer.kt b/src/com/android/customization/picker/notifications/domain/interactor/NotificationsSnapshotRestorer.kt
index c782b74..9dc8872 100644
--- a/src/com/android/customization/picker/notifications/domain/interactor/NotificationsSnapshotRestorer.kt
+++ b/src/com/android/customization/picker/notifications/domain/interactor/NotificationsSnapshotRestorer.kt
@@ -12,24 +12,28 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
- *
*/
package com.android.customization.picker.notifications.domain.interactor
-import com.android.customization.picker.notifications.shared.model.NotificationSettingsModel
+import com.android.systemui.shared.notifications.domain.interactor.NotificationSettingsInteractor
+import com.android.systemui.shared.notifications.shared.model.NotificationSettingsModel
+import com.android.wallpaper.picker.di.modules.BackgroundDispatcher
import com.android.wallpaper.picker.undo.domain.interactor.SnapshotRestorer
import com.android.wallpaper.picker.undo.domain.interactor.SnapshotStore
import com.android.wallpaper.picker.undo.shared.model.RestorableSnapshot
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
/** Handles state restoration for notification settings. */
class NotificationsSnapshotRestorer(
- private val interactor: NotificationsInteractor,
+ private val interactor: NotificationSettingsInteractor,
+ @BackgroundDispatcher private val backgroundScope: CoroutineScope,
) : SnapshotRestorer {
private var snapshotStore: SnapshotStore = SnapshotStore.NOOP
- fun storeSnapshot(model: NotificationSettingsModel) {
+ private fun storeSnapshot(model: NotificationSettingsModel) {
snapshotStore.store(snapshot(model))
}
@@ -37,6 +41,7 @@
store: SnapshotStore,
): RestorableSnapshot {
snapshotStore = store
+ backgroundScope.launch { interactor.settings.collect { model -> storeSnapshot(model) } }
return snapshot(interactor.getSettings())
}
diff --git a/src/com/android/customization/picker/notifications/shared/model/NotificationSettingsModel.kt b/src/com/android/customization/picker/notifications/shared/model/NotificationSettingsModel.kt
deleted file mode 100644
index 7ce388b..0000000
--- a/src/com/android/customization/picker/notifications/shared/model/NotificationSettingsModel.kt
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package com.android.customization.picker.notifications.shared.model
-
-/** Models notification settings. */
-data class NotificationSettingsModel(
- /** Whether notifications are shown on the lock screen. */
- val isShowNotificationsOnLockScreenEnabled: Boolean = false,
-)
diff --git a/src/com/android/customization/picker/notifications/ui/viewmodel/NotificationSectionViewModel.kt b/src/com/android/customization/picker/notifications/ui/viewmodel/NotificationSectionViewModel.kt
index 1a5254f..86a2693 100644
--- a/src/com/android/customization/picker/notifications/ui/viewmodel/NotificationSectionViewModel.kt
+++ b/src/com/android/customization/picker/notifications/ui/viewmodel/NotificationSectionViewModel.kt
@@ -22,7 +22,7 @@
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import com.android.customization.module.logging.ThemesUserEventLogger
-import com.android.customization.picker.notifications.domain.interactor.NotificationsInteractor
+import com.android.systemui.shared.notifications.domain.interactor.NotificationSettingsInteractor
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
@@ -31,7 +31,7 @@
class NotificationSectionViewModel
@VisibleForTesting
constructor(
- private val interactor: NotificationsInteractor,
+ private val interactor: NotificationSettingsInteractor,
private val logger: ThemesUserEventLogger,
) : ViewModel() {
@@ -50,7 +50,7 @@
}
class Factory(
- private val interactor: NotificationsInteractor,
+ private val interactor: NotificationSettingsInteractor,
private val logger: ThemesUserEventLogger,
) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
diff --git a/tests/Android.bp b/tests/Android.bp
index 74dc6a1..33f1c3f 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -47,6 +47,7 @@
"WallpaperPicker2TestLib",
"WallpaperPicker2TestRunner",
"ThemePickerTestLib",
+ "SystemUICustomizationTestUtils",
"androidx.test.espresso.core",
"androidx.test.espresso.contrib",
"androidx.test.espresso.intents",
diff --git a/tests/robotests/Android.bp b/tests/robotests/Android.bp
index d4dde59..296d2ca 100644
--- a/tests/robotests/Android.bp
+++ b/tests/robotests/Android.bp
@@ -24,6 +24,7 @@
"junit",
"kotlinx_coroutines_test",
"truth",
+ "SystemUICustomizationTestUtils",
],
libs: [
diff --git a/tests/robotests/src/com/android/customization/picker/notifications/ui/viewmodel/NotificationSectionViewModelTest.kt b/tests/robotests/src/com/android/customization/picker/notifications/ui/viewmodel/NotificationSectionViewModelTest.kt
index 1ff1fc8..8966de5 100644
--- a/tests/robotests/src/com/android/customization/picker/notifications/ui/viewmodel/NotificationSectionViewModelTest.kt
+++ b/tests/robotests/src/com/android/customization/picker/notifications/ui/viewmodel/NotificationSectionViewModelTest.kt
@@ -20,16 +20,13 @@
import androidx.test.filters.SmallTest
import com.android.customization.module.logging.TestThemesUserEventLogger
import com.android.customization.module.logging.ThemesUserEventLogger
-import com.android.customization.picker.notifications.data.repository.NotificationsRepository
-import com.android.customization.picker.notifications.domain.interactor.NotificationsInteractor
-import com.android.customization.picker.notifications.domain.interactor.NotificationsSnapshotRestorer
-import com.android.wallpaper.testing.FakeSecureSettingsRepository
-import com.android.wallpaper.testing.FakeSnapshotStore
+import com.android.systemui.shared.notifications.data.repository.NotificationSettingsRepository
+import com.android.systemui.shared.notifications.domain.interactor.NotificationSettingsInteractor
+import com.android.systemui.shared.settings.data.repository.FakeSecureSettingsRepository
import com.android.wallpaper.testing.collectLastValue
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.resetMain
@@ -51,7 +48,7 @@
private lateinit var underTest: NotificationSectionViewModel
private lateinit var testScope: TestScope
- private lateinit var interactor: NotificationsInteractor
+ private lateinit var interactor: NotificationSettingsInteractor
@Before
fun setUp() {
@@ -59,19 +56,13 @@
Dispatchers.setMain(testDispatcher)
testScope = TestScope(testDispatcher)
interactor =
- NotificationsInteractor(
+ NotificationSettingsInteractor(
repository =
- NotificationsRepository(
+ NotificationSettingsRepository(
scope = testScope.backgroundScope,
backgroundDispatcher = testDispatcher,
secureSettingsRepository = FakeSecureSettingsRepository(),
),
- snapshotRestorer = {
- NotificationsSnapshotRestorer(
- interactor = interactor,
- )
- .apply { runBlocking { setUpSnapshotRestorer(FakeSnapshotStore()) } }
- },
)
underTest =
diff --git a/tests/robotests/src/com/android/customization/picker/notifications/data/repository/NotificationsRepositoryTest.kt b/tests/robotests/src/com/android/customization/picker/repository/NotificationSettingsRepositoryTest.kt
similarity index 85%
rename from tests/robotests/src/com/android/customization/picker/notifications/data/repository/NotificationsRepositoryTest.kt
rename to tests/robotests/src/com/android/customization/picker/repository/NotificationSettingsRepositoryTest.kt
index be799db..bb6f292 100644
--- a/tests/robotests/src/com/android/customization/picker/notifications/data/repository/NotificationsRepositoryTest.kt
+++ b/tests/robotests/src/com/android/customization/picker/repository/NotificationSettingsRepositoryTest.kt
@@ -12,18 +12,17 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
- *
*/
-package com.android.customization.picker.notifications.data.repository
+package com.android.customization.picker.repository
import android.provider.Settings
import androidx.test.filters.SmallTest
-import com.android.customization.picker.notifications.shared.model.NotificationSettingsModel
-import com.android.wallpaper.testing.FakeSecureSettingsRepository
+import com.android.systemui.shared.notifications.data.repository.NotificationSettingsRepository
+import com.android.systemui.shared.notifications.shared.model.NotificationSettingsModel
+import com.android.systemui.shared.settings.data.repository.FakeSecureSettingsRepository
import com.android.wallpaper.testing.collectLastValue
import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest
@@ -32,12 +31,11 @@
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
-@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(JUnit4::class)
-class NotificationsRepositoryTest {
+class NotificationSettingsRepositoryTest {
- private lateinit var underTest: NotificationsRepository
+ private lateinit var underTest: NotificationSettingsRepository
private lateinit var testScope: TestScope
private lateinit var secureSettingsRepository: FakeSecureSettingsRepository
@@ -49,7 +47,7 @@
secureSettingsRepository = FakeSecureSettingsRepository()
underTest =
- NotificationsRepository(
+ NotificationSettingsRepository(
scope = testScope.backgroundScope,
backgroundDispatcher = testDispatcher,
secureSettingsRepository = secureSettingsRepository,