diff options
| author | 2024-04-03 20:38:21 +0000 | |
|---|---|---|
| committer | 2024-04-03 20:38:21 +0000 | |
| commit | 6e887ee1e10fed8e1eac460f343d33abce09ff88 (patch) | |
| tree | 63374ab788081a8b872538d80b9e2f9c154962bc | |
| parent | ef9a6d7c37cbb5a2819faca06a24886e9e4fb5bc (diff) | |
| parent | 8744ef63202774408dda38d74d353dc0ccd070e8 (diff) | |
Merge "Bakup and restore communal shared preferences" into main
4 files changed, 137 insertions, 11 deletions
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalPrefsRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalPrefsRepositoryImplTest.kt index 6bff0dc7bd9e..5e120b5f9560 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalPrefsRepositoryImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalPrefsRepositoryImplTest.kt @@ -16,11 +16,15 @@ package com.android.systemui.communal.data.repository +import android.content.Context +import android.content.Intent import android.content.SharedPreferences import android.content.pm.UserInfo import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase +import com.android.systemui.backup.BackupHelper +import com.android.systemui.broadcast.broadcastDispatcher import com.android.systemui.communal.data.repository.CommunalPrefsRepositoryImpl.Companion.FILE_NAME import com.android.systemui.coroutines.collectLastValue import com.android.systemui.kosmos.testDispatcher @@ -34,16 +38,22 @@ import com.android.systemui.user.data.repository.fakeUserRepository import com.android.systemui.util.FakeSharedPreferences import com.google.common.truth.Truth.assertThat import java.io.File +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock +import org.mockito.Mockito +import org.mockito.Mockito.atLeastOnce +import org.mockito.Mockito.clearInvocations +import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations +@OptIn(ExperimentalCoroutinesApi::class) @SmallTest @RunWith(AndroidJUnit4::class) -@android.platform.test.annotations.EnabledOnRavenwood class CommunalPrefsRepositoryImplTest : SysuiTestCase() { @Mock private lateinit var tableLogBuffer: TableLogBuffer @@ -69,20 +79,12 @@ class CommunalPrefsRepositoryImplTest : SysuiTestCase() { USER_INFOS[1].id to FakeSharedPreferences() ) ) - underTest = - CommunalPrefsRepositoryImpl( - testScope.backgroundScope, - kosmos.testDispatcher, - userRepository, - userFileManager, - logcatLogBuffer("CommunalPrefsRepositoryImplTest"), - tableLogBuffer, - ) } @Test fun isCtaDismissedValue_byDefault_isFalse() = testScope.runTest { + underTest = createCommunalPrefsRepositoryImpl(userFileManager) val isCtaDismissed by collectLastValue(underTest.isCtaDismissed) assertThat(isCtaDismissed).isFalse() } @@ -90,6 +92,7 @@ class CommunalPrefsRepositoryImplTest : SysuiTestCase() { @Test fun isCtaDismissedValue_onSet_isTrue() = testScope.runTest { + underTest = createCommunalPrefsRepositoryImpl(userFileManager) val isCtaDismissed by collectLastValue(underTest.isCtaDismissed) underTest.setCtaDismissedForCurrentUser() @@ -99,6 +102,7 @@ class CommunalPrefsRepositoryImplTest : SysuiTestCase() { @Test fun isCtaDismissedValue_whenSwitchUser() = testScope.runTest { + underTest = createCommunalPrefsRepositoryImpl(userFileManager) val isCtaDismissed by collectLastValue(underTest.isCtaDismissed) underTest.setCtaDismissedForCurrentUser() @@ -118,6 +122,44 @@ class CommunalPrefsRepositoryImplTest : SysuiTestCase() { assertThat(isCtaDismissed).isTrue() } + @Test + fun getSharedPreferences_whenFileRestored() = + testScope.runTest { + val userFileManagerSpy = Mockito.spy(userFileManager) + underTest = createCommunalPrefsRepositoryImpl(userFileManagerSpy) + + val isCtaDismissed by collectLastValue(underTest.isCtaDismissed) + userRepository.setSelectedUserInfo(USER_INFOS[0]) + assertThat(isCtaDismissed).isFalse() + clearInvocations(userFileManagerSpy) + + // Received restore finished event. + kosmos.broadcastDispatcher.sendIntentToMatchingReceiversOnly( + context, + Intent(BackupHelper.ACTION_RESTORE_FINISHED), + ) + runCurrent() + + // Get shared preferences from the restored file. + verify(userFileManagerSpy, atLeastOnce()) + .getSharedPreferences( + FILE_NAME, + Context.MODE_PRIVATE, + userRepository.getSelectedUserInfo().id + ) + } + + private fun createCommunalPrefsRepositoryImpl(userFileManager: UserFileManager) = + CommunalPrefsRepositoryImpl( + testScope.backgroundScope, + kosmos.testDispatcher, + userRepository, + userFileManager, + kosmos.broadcastDispatcher, + logcatLogBuffer("CommunalPrefsRepositoryImplTest"), + tableLogBuffer, + ) + private class FakeUserFileManager(private val sharedPrefs: Map<Int, SharedPreferences>) : UserFileManager { override fun getFile(fileName: String, userId: Int): File { diff --git a/packages/SystemUI/src/com/android/systemui/backup/BackupHelper.kt b/packages/SystemUI/src/com/android/systemui/backup/BackupHelper.kt index c4d282e24a92..a667de2351d7 100644 --- a/packages/SystemUI/src/com/android/systemui/backup/BackupHelper.kt +++ b/packages/SystemUI/src/com/android/systemui/backup/BackupHelper.kt @@ -28,10 +28,14 @@ import android.os.ParcelFileDescriptor import android.os.UserHandle import android.util.Log import com.android.app.tracing.traceSection +import com.android.systemui.Flags.communalHub +import com.android.systemui.backup.BackupHelper.Companion.ACTION_RESTORE_FINISHED +import com.android.systemui.communal.domain.backup.CommunalPrefsBackupHelper import com.android.systemui.controls.controller.AuxiliaryPersistenceWrapper import com.android.systemui.controls.controller.ControlsFavoritePersistenceWrapper import com.android.systemui.keyguard.domain.backup.KeyguardQuickAffordanceBackupHelper import com.android.systemui.people.widget.PeopleBackupHelper +import com.android.systemui.res.R import com.android.systemui.settings.UserFileManagerImpl /** @@ -53,6 +57,8 @@ open class BackupHelper : BackupAgentHelper() { private const val PEOPLE_TILES_BACKUP_KEY = "systemui.people.shared_preferences" private const val KEYGUARD_QUICK_AFFORDANCES_BACKUP_KEY = "systemui.keyguard.quickaffordance.shared_preferences" + private const val COMMUNAL_PREFS_BACKUP_KEY = + "systemui.communal.shared_preferences" val controlsDataLock = Any() const val ACTION_RESTORE_FINISHED = "com.android.systemui.backup.RESTORE_FINISHED" const val PERMISSION_SELF = "com.android.systemui.permission.SELF" @@ -75,6 +81,15 @@ open class BackupHelper : BackupAgentHelper() { userId = userHandle.identifier, ), ) + if (communalEnabled()) { + addHelper( + COMMUNAL_PREFS_BACKUP_KEY, + CommunalPrefsBackupHelper( + context = this, + userId = userHandle.identifier, + ) + ) + } } override fun onRestoreFinished() { @@ -100,6 +115,10 @@ open class BackupHelper : BackupAgentHelper() { } } + private fun communalEnabled(): Boolean { + return resources.getBoolean(R.bool.config_communalServiceEnabled) && communalHub() + } + /** * Helper class for restoring files ONLY if they are not present. * diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalPrefsRepository.kt b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalPrefsRepository.kt index 0e9b32ffd12a..40d744015498 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalPrefsRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalPrefsRepository.kt @@ -17,8 +17,11 @@ package com.android.systemui.communal.data.repository import android.content.Context +import android.content.IntentFilter import android.content.SharedPreferences import android.content.pm.UserInfo +import com.android.systemui.backup.BackupHelper +import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.log.LogBuffer @@ -30,15 +33,18 @@ import com.android.systemui.log.table.logDiffsForTable import com.android.systemui.settings.UserFileManager import com.android.systemui.user.data.repository.UserRepository import com.android.systemui.util.kotlin.SharedPreferencesExt.observe +import com.android.systemui.util.kotlin.emitOnStart import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.withContext @@ -65,14 +71,36 @@ constructor( @Background private val bgDispatcher: CoroutineDispatcher, private val userRepository: UserRepository, private val userFileManager: UserFileManager, + broadcastDispatcher: BroadcastDispatcher, @CommunalLog logBuffer: LogBuffer, @CommunalTableLog tableLogBuffer: TableLogBuffer, ) : CommunalPrefsRepository { private val logger = Logger(logBuffer, "CommunalPrefsRepositoryImpl") + /** + * Emits an event each time a Backup & Restore restoration job is completed. Does not emit an + * initial value. + */ + private val backupRestorationEvents: Flow<Unit> = + broadcastDispatcher.broadcastFlow( + filter = IntentFilter(BackupHelper.ACTION_RESTORE_FINISHED), + flags = Context.RECEIVER_NOT_EXPORTED, + permission = BackupHelper.PERMISSION_SELF, + ) + override val isCtaDismissed: Flow<Boolean> = - userRepository.selectedUserInfo + combine( + userRepository.selectedUserInfo, + // Make sure combine can emit even if we never get a Backup & Restore event, + // which is the most common case as restoration only happens on initial device + // setup. + backupRestorationEvents.emitOnStart().onEach { + logger.i("Restored state for communal preferences.") + }, + ) { user, _ -> + user + } .flatMapLatest(::observeCtaDismissState) .logDiffsForTable( tableLogBuffer = tableLogBuffer, diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/backup/CommunalPrefsBackupHelper.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/backup/CommunalPrefsBackupHelper.kt new file mode 100644 index 000000000000..55c6ec88bd11 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/communal/domain/backup/CommunalPrefsBackupHelper.kt @@ -0,0 +1,37 @@ +/* + * 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.systemui.communal.domain.backup + +import android.app.backup.SharedPreferencesBackupHelper +import android.content.Context +import com.android.systemui.communal.data.repository.CommunalPrefsRepositoryImpl.Companion.FILE_NAME +import com.android.systemui.settings.UserFileManagerImpl + +/** Helper to backup & restore the shared preferences in glanceable hub for the current user. */ +class CommunalPrefsBackupHelper( + context: Context, + userId: Int, +) : + SharedPreferencesBackupHelper( + context, + UserFileManagerImpl.createFile( + userId = userId, + fileName = FILE_NAME, + ) + .path + ) |