Fix notifications undo system (1/2)
Adjust so NotficationSettingsRepository in frameworks/base emits the
show notifications boolean in a suspend function, after it is retrieved
from SecureSettingsRepository, instead of returning a default value
immediately.
Also added missing test NotificationsSnapshotRestorerTest.
Flag: EXEMPT bug fix
Bug: 326440143
Test: manually verified notifications toggle sets and resets correctly
Test: manually verified reset button shows and hides correctly
Test: existing notifications unit tests pass
Test: new ThemePicker test NotificationsSnapshotRestorerTest
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:4d4aaff7a74842e1ea32c6038caad878fd7bfeb8)
Merged-In: If580a54fdb920a6a17f7c605caf5359a868f0ec0
Change-Id: If580a54fdb920a6a17f7c605caf5359a868f0ec0
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 09d2d29..e82d00a 100644
--- a/src/com/android/customization/picker/notifications/domain/interactor/NotificationsSnapshotRestorer.kt
+++ b/src/com/android/customization/picker/notifications/domain/interactor/NotificationsSnapshotRestorer.kt
@@ -40,16 +40,19 @@
store: SnapshotStore,
): RestorableSnapshot {
snapshotStore = store
- backgroundScope.launch {
- interactor.isShowNotificationsOnLockScreenEnabled.collect {
- storeSnapshot(
- NotificationSnapshotModel(isShowNotificationsOnLockScreenEnabled = it)
- )
- }
- }
+ // The initial snapshot should be returned and stored before storing additional snapshots.
return snapshot(
- NotificationSnapshotModel(interactor.isShowNotificationsOnLockScreenEnabled.value)
- )
+ NotificationSnapshotModel(interactor.isShowNotificationsOnLockScreenEnabled().value)
+ )
+ .also {
+ backgroundScope.launch {
+ interactor.isShowNotificationsOnLockScreenEnabled().collect {
+ storeSnapshot(
+ NotificationSnapshotModel(isShowNotificationsOnLockScreenEnabled = it)
+ )
+ }
+ }
+ }
}
override suspend fun restoreToSnapshot(snapshot: RestorableSnapshot) {
diff --git a/src/com/android/customization/picker/notifications/ui/binder/NotificationSectionBinder.kt b/src/com/android/customization/picker/notifications/ui/binder/NotificationSectionBinder.kt
index 8f2727c..baf7bbf 100644
--- a/src/com/android/customization/picker/notifications/ui/binder/NotificationSectionBinder.kt
+++ b/src/com/android/customization/picker/notifications/ui/binder/NotificationSectionBinder.kt
@@ -44,7 +44,7 @@
lifecycleOwner.lifecycleScope.launch {
lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
- launch { viewModel.isSwitchOn.collect { switch.isChecked = it } }
+ launch { viewModel.isSwitchOn().collect { switch.isChecked = it } }
}
}
}
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 5db7626..022dc9b 100644
--- a/src/com/android/customization/picker/notifications/ui/viewmodel/NotificationSectionViewModel.kt
+++ b/src/com/android/customization/picker/notifications/ui/viewmodel/NotificationSectionViewModel.kt
@@ -35,14 +35,14 @@
) : ViewModel() {
/** Whether the switch should be on. */
- val isSwitchOn: Flow<Boolean> = interactor.isShowNotificationsOnLockScreenEnabled
+ suspend fun isSwitchOn(): Flow<Boolean> = interactor.isShowNotificationsOnLockScreenEnabled()
/** Notifies that the section has been clicked. */
fun onClicked() {
viewModelScope.launch {
interactor.toggleShowNotificationsOnLockscreenEnabled()
logger.logLockScreenNotificationApplied(
- interactor.isShowNotificationsOnLockScreenEnabled.value
+ interactor.isShowNotificationsOnLockScreenEnabled().value
)
}
}
diff --git a/tests/robotests/src/com/android/customization/model/notifications/domain/interactor/NotificationsSnapshotRestorerTest.kt b/tests/robotests/src/com/android/customization/model/notifications/domain/interactor/NotificationsSnapshotRestorerTest.kt
new file mode 100644
index 0000000..bf8cfda
--- /dev/null
+++ b/tests/robotests/src/com/android/customization/model/notifications/domain/interactor/NotificationsSnapshotRestorerTest.kt
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2024 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.model.notifications.domain.interactor
+
+import android.provider.Settings
+import androidx.test.filters.SmallTest
+import com.android.customization.picker.notifications.domain.interactor.NotificationsSnapshotRestorer
+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.FakeSnapshotStore
+import com.android.wallpaper.testing.collectLastValue
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runTest
+import kotlinx.coroutines.test.setMain
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.robolectric.RobolectricTestRunner
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(RobolectricTestRunner::class)
+class NotificationsSnapshotRestorerTest {
+
+ private lateinit var underTest: NotificationsSnapshotRestorer
+ private lateinit var fakeSecureSettingsRepository: FakeSecureSettingsRepository
+ private lateinit var interactor: NotificationSettingsInteractor
+
+ private lateinit var testScope: TestScope
+
+ @Before
+ fun setUp() {
+ val testDispatcher = StandardTestDispatcher()
+ Dispatchers.setMain(testDispatcher)
+ testScope = TestScope(testDispatcher)
+ fakeSecureSettingsRepository = FakeSecureSettingsRepository()
+ interactor =
+ NotificationSettingsInteractor(
+ repository =
+ NotificationSettingsRepository(
+ scope = testScope.backgroundScope,
+ backgroundDispatcher = testDispatcher,
+ secureSettingsRepository = fakeSecureSettingsRepository,
+ ),
+ )
+ underTest =
+ NotificationsSnapshotRestorer(
+ interactor = interactor,
+ backgroundScope = testScope.backgroundScope
+ )
+ }
+
+ @Test
+ fun setUpAndRestore_Active() =
+ testScope.runTest {
+ fakeSecureSettingsRepository.setInt(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 1)
+ val showNotifs = collectLastValue(interactor.isShowNotificationsOnLockScreenEnabled())
+
+ val store = FakeSnapshotStore()
+ store.store(underTest.setUpSnapshotRestorer(store = store))
+ val initialSnapshot = store.retrieve()
+ underTest.restoreToSnapshot(snapshot = initialSnapshot)
+
+ assertThat(showNotifs()).isTrue()
+ }
+
+ @Test
+ fun setUpAndRestore_Inactive() =
+ testScope.runTest {
+ fakeSecureSettingsRepository.setInt(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0)
+ val showNotifs = collectLastValue(interactor.isShowNotificationsOnLockScreenEnabled())
+
+ val store = FakeSnapshotStore()
+ store.store(underTest.setUpSnapshotRestorer(store = store))
+ val initialSnapshot = store.retrieve()
+ underTest.restoreToSnapshot(snapshot = initialSnapshot)
+
+ assertThat(showNotifs()).isFalse()
+ }
+
+ @Test
+ fun setUp_deactivate_restoreToActive() = runTest {
+ fakeSecureSettingsRepository.setInt(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 1)
+ val showNotifs = collectLastValue(interactor.isShowNotificationsOnLockScreenEnabled())
+ val store = FakeSnapshotStore()
+ store.store(underTest.setUpSnapshotRestorer(store = store))
+ val initialSnapshot = store.retrieve()
+
+ fakeSecureSettingsRepository.setInt(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0)
+ underTest.restoreToSnapshot(snapshot = initialSnapshot)
+
+ assertThat(showNotifs()).isTrue()
+ }
+
+ @Test
+ fun setUp_activate_restoreToInactive() = runTest {
+ fakeSecureSettingsRepository.setInt(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0)
+ val showNotifs = collectLastValue(interactor.isShowNotificationsOnLockScreenEnabled())
+ val store = FakeSnapshotStore()
+ store.store(underTest.setUpSnapshotRestorer(store = store))
+ val initialSnapshot = store.retrieve()
+
+ fakeSecureSettingsRepository.setInt(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 1)
+ underTest.restoreToSnapshot(snapshot = initialSnapshot)
+
+ assertThat(showNotifs()).isFalse()
+ }
+}
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 8966de5..e9f7ffd 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
@@ -80,7 +80,7 @@
@Test
fun `toggles back and forth`() =
testScope.runTest {
- val isSwitchOn = collectLastValue(underTest.isSwitchOn)
+ val isSwitchOn = collectLastValue(underTest.isSwitchOn())
val initialIsSwitchOn = isSwitchOn()