diff options
| author | 2023-02-15 15:06:08 +0000 | |
|---|---|---|
| committer | 2023-02-15 15:06:08 +0000 | |
| commit | cb5228cf3fc7c6b439222e825c57c265553bd8b8 (patch) | |
| tree | 6c49c55875026b06e569cb1f06851f579783d11c | |
| parent | e2a2e37c5e049cbe2a55162a287fd642f3639f93 (diff) | |
| parent | 7a8c125e88f7a251a1ee2eb0af77803a00362977 (diff) | |
Merge "Backup and restore - Fix non-system users" into tm-qpr-dev
6 files changed, 246 insertions, 199 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/backup/BackupHelper.kt b/packages/SystemUI/src/com/android/systemui/backup/BackupHelper.kt index 621b99d6804a..6721c5d5e413 100644 --- a/packages/SystemUI/src/com/android/systemui/backup/BackupHelper.kt +++ b/packages/SystemUI/src/com/android/systemui/backup/BackupHelper.kt @@ -31,6 +31,7 @@ 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.settings.UserFileManagerImpl /** * Helper for backing up elements in SystemUI @@ -58,17 +59,8 @@ open class BackupHelper : BackupAgentHelper() { override fun onCreate(userHandle: UserHandle, operationType: Int) { super.onCreate() - // The map in mapOf is guaranteed to be order preserving - val controlsMap = mapOf(CONTROLS to getPPControlsFile(this)) - NoOverwriteFileBackupHelper(controlsDataLock, this, controlsMap).also { - addHelper(NO_OVERWRITE_FILES_BACKUP_KEY, it) - } - // Conversations widgets backup only works for system user, because widgets' information is - // stored in system user's SharedPreferences files and we can't open those from other users. - if (!userHandle.isSystem) { - return - } + addControlsHelper(userHandle.identifier) val keys = PeopleBackupHelper.getFilesToBackup() addHelper( @@ -95,6 +87,18 @@ open class BackupHelper : BackupAgentHelper() { sendBroadcastAsUser(intent, UserHandle.SYSTEM, PERMISSION_SELF) } + private fun addControlsHelper(userId: Int) { + val file = UserFileManagerImpl.createFile( + userId = userId, + fileName = CONTROLS, + ) + // The map in mapOf is guaranteed to be order preserving + val controlsMap = mapOf(file.getPath() to getPPControlsFile(this, userId)) + NoOverwriteFileBackupHelper(controlsDataLock, this, controlsMap).also { + addHelper(NO_OVERWRITE_FILES_BACKUP_KEY, it) + } + } + /** * Helper class for restoring files ONLY if they are not present. * @@ -136,17 +140,21 @@ open class BackupHelper : BackupAgentHelper() { } } -private fun getPPControlsFile(context: Context): () -> Unit { +private fun getPPControlsFile(context: Context, userId: Int): () -> Unit { return { - val filesDir = context.filesDir - val file = Environment.buildPath(filesDir, BackupHelper.CONTROLS) + val file = UserFileManagerImpl.createFile( + userId = userId, + fileName = BackupHelper.CONTROLS, + ) if (file.exists()) { - val dest = - Environment.buildPath(filesDir, AuxiliaryPersistenceWrapper.AUXILIARY_FILE_NAME) + val dest = UserFileManagerImpl.createFile( + userId = userId, + fileName = AuxiliaryPersistenceWrapper.AUXILIARY_FILE_NAME, + ) file.copyTo(dest) val jobScheduler = context.getSystemService(JobScheduler::class.java) jobScheduler?.schedule( - AuxiliaryPersistenceWrapper.DeletionJobService.getJobForContext(context) + AuxiliaryPersistenceWrapper.DeletionJobService.getJobForContext(context, userId) ) } } diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/AuxiliaryPersistenceWrapper.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/AuxiliaryPersistenceWrapper.kt index 0a6335e01f9f..b3c18fb3cd98 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/controller/AuxiliaryPersistenceWrapper.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/controller/AuxiliaryPersistenceWrapper.kt @@ -21,8 +21,10 @@ import android.app.job.JobParameters import android.app.job.JobService import android.content.ComponentName import android.content.Context +import android.os.PersistableBundle import com.android.internal.annotations.VisibleForTesting import com.android.systemui.backup.BackupHelper +import com.android.systemui.settings.UserFileManagerImpl import java.io.File import java.util.concurrent.Executor import java.util.concurrent.TimeUnit @@ -33,14 +35,14 @@ import java.util.concurrent.TimeUnit * This file is a copy of the `controls_favorites.xml` file restored from a back up. It is used to * keep track of controls that were restored but its corresponding app has not been installed yet. */ -class AuxiliaryPersistenceWrapper @VisibleForTesting internal constructor( - wrapper: ControlsFavoritePersistenceWrapper -) { +class AuxiliaryPersistenceWrapper +@VisibleForTesting +internal constructor(wrapper: ControlsFavoritePersistenceWrapper) { constructor( file: File, executor: Executor - ): this(ControlsFavoritePersistenceWrapper(file, executor)) + ) : this(ControlsFavoritePersistenceWrapper(file, executor)) companion object { const val AUXILIARY_FILE_NAME = "aux_controls_favorites.xml" @@ -48,9 +50,7 @@ class AuxiliaryPersistenceWrapper @VisibleForTesting internal constructor( private var persistenceWrapper: ControlsFavoritePersistenceWrapper = wrapper - /** - * Access the current list of favorites as tracked by the auxiliary file - */ + /** Access the current list of favorites as tracked by the auxiliary file */ var favorites: List<StructureInfo> = emptyList() private set @@ -73,18 +73,19 @@ class AuxiliaryPersistenceWrapper @VisibleForTesting internal constructor( * exist, it will be initialized to an empty list. */ fun initialize() { - favorites = if (persistenceWrapper.fileExists) { - persistenceWrapper.readFavorites() - } else { - emptyList() - } + favorites = + if (persistenceWrapper.fileExists) { + persistenceWrapper.readFavorites() + } else { + emptyList() + } } /** * Gets the list of favorite controls as persisted in the auxiliary file for a given component. * - * When the favorites for that application are returned, they will be removed from the - * auxiliary file immediately, so they won't be retrieved again. + * When the favorites for that application are returned, they will be removed from the auxiliary + * file immediately, so they won't be retrieved again. * @param componentName the name of the service that provided the controls * @return a list of structures with favorites */ @@ -103,20 +104,20 @@ class AuxiliaryPersistenceWrapper @VisibleForTesting internal constructor( } } - /** - * [JobService] to delete the auxiliary file after a week. - */ + /** [JobService] to delete the auxiliary file after a week. */ class DeletionJobService : JobService() { companion object { - @VisibleForTesting - internal val DELETE_FILE_JOB_ID = 1000 + @VisibleForTesting internal val DELETE_FILE_JOB_ID = 1000 + @VisibleForTesting internal val USER = "USER" private val WEEK_IN_MILLIS = TimeUnit.DAYS.toMillis(7) - fun getJobForContext(context: Context): JobInfo { + fun getJobForContext(context: Context, targetUserId: Int): JobInfo { val jobId = DELETE_FILE_JOB_ID + context.userId val componentName = ComponentName(context, DeletionJobService::class.java) + val bundle = PersistableBundle().also { it.putInt(USER, targetUserId) } return JobInfo.Builder(jobId, componentName) .setMinimumLatency(WEEK_IN_MILLIS) .setPersisted(true) + .setExtras(bundle) .build() } } @@ -127,8 +128,14 @@ class AuxiliaryPersistenceWrapper @VisibleForTesting internal constructor( } override fun onStartJob(params: JobParameters): Boolean { + val userId = params.getExtras()?.getInt(USER, 0) ?: 0 synchronized(BackupHelper.controlsDataLock) { - baseContext.deleteFile(AUXILIARY_FILE_NAME) + val file = + UserFileManagerImpl.createFile( + userId = userId, + fileName = AUXILIARY_FILE_NAME, + ) + baseContext.deleteFile(file.getPath()) } return false } @@ -137,4 +144,4 @@ class AuxiliaryPersistenceWrapper @VisibleForTesting internal constructor( return true // reschedule and try again if the job was stopped without completing } } -}
\ No newline at end of file +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/backup/KeyguardQuickAffordanceBackupHelper.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/backup/KeyguardQuickAffordanceBackupHelper.kt index 0e865cee0b76..fa6efa504623 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/backup/KeyguardQuickAffordanceBackupHelper.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/backup/KeyguardQuickAffordanceBackupHelper.kt @@ -29,16 +29,9 @@ class KeyguardQuickAffordanceBackupHelper( ) : SharedPreferencesBackupHelper( context, - if (UserFileManagerImpl.isPrimaryUser(userId)) { - KeyguardQuickAffordanceSelectionManager.FILE_NAME - } else { - UserFileManagerImpl.secondaryUserFile( - context = context, - fileName = KeyguardQuickAffordanceSelectionManager.FILE_NAME, - directoryName = UserFileManagerImpl.SHARED_PREFS, - userId = userId, - ) - .also { UserFileManagerImpl.ensureParentDirExists(it) } - .toString() - } + UserFileManagerImpl.createFile( + userId = userId, + fileName = KeyguardQuickAffordanceSelectionManager.FILE_NAME, + ) + .getPath() ) diff --git a/packages/SystemUI/src/com/android/systemui/settings/UserFileManagerImpl.kt b/packages/SystemUI/src/com/android/systemui/settings/UserFileManagerImpl.kt index bfba6dfddfac..bb637dcd860e 100644 --- a/packages/SystemUI/src/com/android/systemui/settings/UserFileManagerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/settings/UserFileManagerImpl.kt @@ -32,74 +32,62 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.util.concurrency.DelayableExecutor import java.io.File +import java.io.FilenameFilter import javax.inject.Inject /** - * Implementation for retrieving file paths for file storage of system and secondary users. Files - * lie in {File Directory}/UserFileManager/{User Id} for secondary user. For system user, we use the - * conventional {File Directory} + * Implementation for retrieving file paths for file storage of system and secondary users. For + * non-system users, files will be prepended by a special prefix containing the user id. */ @SysUISingleton class UserFileManagerImpl @Inject constructor( - // Context of system process and system user. private val context: Context, val userManager: UserManager, val broadcastDispatcher: BroadcastDispatcher, @Background val backgroundExecutor: DelayableExecutor ) : UserFileManager, CoreStartable { companion object { - private const val FILES = "files" + private const val PREFIX = "__USER_" + private const val TAG = "UserFileManagerImpl" + const val ROOT_DIR = "UserFileManager" + const val FILES = "files" const val SHARED_PREFS = "shared_prefs" - @VisibleForTesting internal const val ID = "UserFileManager" - - /** Returns `true` if the given user ID is that for the primary/system user. */ - fun isPrimaryUser(userId: Int): Boolean { - return UserHandle(userId).isSystem - } /** - * Returns a [File] pointing to the correct path for a secondary user ID. - * - * Note that there is no check for the type of user. This should only be called for - * secondary users, never for the system user. For that, make sure to call [isPrimaryUser]. - * - * Note also that there is no guarantee that the parent directory structure for the file - * exists on disk. For that, call [ensureParentDirExists]. - * - * @param context The context - * @param fileName The name of the file - * @param directoryName The name of the directory that would contain the file - * @param userId The ID of the user to build a file path for + * Returns a File object with a relative path, built from the userId for non-system users */ - fun secondaryUserFile( - context: Context, - fileName: String, - directoryName: String, - userId: Int, - ): File { - return Environment.buildPath( - context.filesDir, - ID, - userId.toString(), - directoryName, - fileName, - ) + fun createFile(fileName: String, userId: Int): File { + return if (isSystemUser(userId)) { + File(fileName) + } else { + File(getFilePrefix(userId) + fileName) + } } - /** - * Checks to see if parent dir of the file exists. If it does not, we create the parent dirs - * recursively. - */ - fun ensureParentDirExists(file: File) { - val parent = file.parentFile - if (!parent.exists()) { - if (!parent.mkdirs()) { - Log.e(ID, "Could not create parent directory for file: ${file.absolutePath}") - } + fun createLegacyFile(context: Context, dir: String, fileName: String, userId: Int): File? { + return if (isSystemUser(userId)) { + null + } else { + return Environment.buildPath( + context.filesDir, + ROOT_DIR, + userId.toString(), + dir, + fileName + ) } } + + fun getFilePrefix(userId: Int): String { + return PREFIX + userId.toString() + "_" + } + + /** Returns `true` if the given user ID is that for the system user. */ + private fun isSystemUser(userId: Int): Boolean { + return UserHandle(userId).isSystem + } } private val broadcastReceiver = @@ -119,64 +107,87 @@ constructor( broadcastDispatcher.registerReceiver(broadcastReceiver, filter, backgroundExecutor) } - /** Return the file based on current user. */ + /** + * Return the file based on current user. Files for all users will exist in [context.filesDir], + * but non system user files will be prepended with [getFilePrefix]. + */ override fun getFile(fileName: String, userId: Int): File { - return if (isPrimaryUser(userId)) { - Environment.buildPath(context.filesDir, fileName) - } else { - val secondaryFile = - secondaryUserFile( - context = context, - userId = userId, - directoryName = FILES, - fileName = fileName, - ) - ensureParentDirExists(secondaryFile) - secondaryFile - } + val file = File(context.filesDir, createFile(fileName, userId).path) + createLegacyFile(context, FILES, fileName, userId)?.run { migrate(file, this) } + return file } - /** Get shared preferences from user. */ + /** + * Get shared preferences from user. Files for all users will exist in the shared_prefs dir, but + * non system user files will be prepended with [getFilePrefix]. + */ override fun getSharedPreferences( fileName: String, @Context.PreferencesMode mode: Int, userId: Int ): SharedPreferences { - if (isPrimaryUser(userId)) { - return context.getSharedPreferences(fileName, mode) + val file = createFile(fileName, userId) + createLegacyFile(context, SHARED_PREFS, "$fileName.xml", userId)?.run { + val path = Environment.buildPath(context.dataDir, SHARED_PREFS, "${file.path}.xml") + migrate(path, this) } - - val secondaryUserDir = - secondaryUserFile( - context = context, - fileName = fileName, - directoryName = SHARED_PREFS, - userId = userId, - ) - - ensureParentDirExists(secondaryUserDir) - return context.getSharedPreferences(secondaryUserDir, mode) + return context.getSharedPreferences(file.path, mode) } - /** Remove dirs for deleted users. */ + /** Remove files for deleted users. */ @VisibleForTesting internal fun clearDeletedUserData() { backgroundExecutor.execute { - val file = Environment.buildPath(context.filesDir, ID) - if (!file.exists()) return@execute - val aliveUsers = userManager.aliveUsers.map { it.id.toString() } - val dirsToDelete = file.list().filter { !aliveUsers.contains(it) } + deleteFiles(context.filesDir) + deleteFiles(File(context.dataDir, SHARED_PREFS)) + } + } + + private fun migrate(dest: File, source: File) { + if (source.exists()) { + try { + val parent = source.getParentFile() + source.renameTo(dest) + + deleteParentDirsIfEmpty(parent) + } catch (e: Exception) { + Log.e(TAG, "Failed to rename and delete ${source.path}", e) + } + } + } - dirsToDelete.forEach { dir -> + private fun deleteParentDirsIfEmpty(dir: File?) { + if (dir != null && dir.listFiles().size == 0) { + val priorParent = dir.parentFile + val isRoot = dir.name == ROOT_DIR + dir.delete() + + if (!isRoot) { + deleteParentDirsIfEmpty(priorParent) + } + } + } + + private fun deleteFiles(parent: File) { + val aliveUserFilePrefix = userManager.aliveUsers.map { getFilePrefix(it.id) } + val filesToDelete = + parent.listFiles( + FilenameFilter { _, name -> + name.startsWith(PREFIX) && + aliveUserFilePrefix.filter { name.startsWith(it) }.isEmpty() + } + ) + + // This can happen in test environments + if (filesToDelete == null) { + Log.i(TAG, "Empty directory: ${parent.path}") + } else { + filesToDelete.forEach { file -> + Log.i(TAG, "Deleting file: ${file.path}") try { - val dirToDelete = - Environment.buildPath( - file, - dir, - ) - dirToDelete.deleteRecursively() + file.delete() } catch (e: Exception) { - Log.e(ID, "Deletion failed.", e) + Log.e(TAG, "Deletion failed.", e) } } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/DeletionJobServiceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/DeletionJobServiceTest.kt index 4439586497ff..228374671ad4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/DeletionJobServiceTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/DeletionJobServiceTest.kt @@ -18,9 +18,13 @@ package com.android.systemui.controls.controller import android.app.job.JobParameters import android.content.Context +import android.os.PersistableBundle import android.testing.AndroidTestingRunner import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase +import com.android.systemui.controls.controller.AuxiliaryPersistenceWrapper.DeletionJobService.Companion.USER +import com.android.systemui.util.mockito.whenever +import java.util.concurrent.TimeUnit import org.junit.Assert.assertEquals import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue @@ -28,18 +32,15 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock -import org.mockito.Mockito.`when` import org.mockito.Mockito.mock import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations -import java.util.concurrent.TimeUnit @SmallTest @RunWith(AndroidTestingRunner::class) class DeletionJobServiceTest : SysuiTestCase() { - @Mock - private lateinit var context: Context + @Mock private lateinit var context: Context private lateinit var service: AuxiliaryPersistenceWrapper.DeletionJobService @@ -53,6 +54,10 @@ class DeletionJobServiceTest : SysuiTestCase() { @Test fun testOnStartJob() { + val bundle = PersistableBundle().also { it.putInt(USER, 0) } + val params = mock(JobParameters::class.java) + whenever(params.getExtras()).thenReturn(bundle) + // false means job is terminated assertFalse(service.onStartJob(mock(JobParameters::class.java))) verify(context).deleteFile(AuxiliaryPersistenceWrapper.AUXILIARY_FILE_NAME) @@ -67,13 +72,17 @@ class DeletionJobServiceTest : SysuiTestCase() { @Test fun testJobHasRightParameters() { val userId = 10 - `when`(context.userId).thenReturn(userId) - `when`(context.packageName).thenReturn(mContext.packageName) + whenever(context.userId).thenReturn(userId) + whenever(context.packageName).thenReturn(mContext.packageName) - val jobInfo = AuxiliaryPersistenceWrapper.DeletionJobService.getJobForContext(context) + val jobInfo = + AuxiliaryPersistenceWrapper.DeletionJobService.getJobForContext(context, userId) assertEquals( - AuxiliaryPersistenceWrapper.DeletionJobService.DELETE_FILE_JOB_ID + userId, jobInfo.id) + AuxiliaryPersistenceWrapper.DeletionJobService.DELETE_FILE_JOB_ID + userId, + jobInfo.id + ) assertTrue(jobInfo.isPersisted) + assertEquals(userId, jobInfo.getExtras().getInt(USER)) assertEquals(TimeUnit.DAYS.toMillis(7), jobInfo.minLatencyMillis) } -}
\ No newline at end of file +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/UserFileManagerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/settings/UserFileManagerImplTest.kt index 020a86611552..3fd19ff1827b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/settings/UserFileManagerImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/settings/UserFileManagerImplTest.kt @@ -30,12 +30,14 @@ import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.eq import com.android.systemui.util.time.FakeSystemClock import com.google.common.truth.Truth.assertThat +import java.io.File +import java.nio.file.Files import java.util.concurrent.Executor -import org.junit.After import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock +import org.mockito.Mockito.atLeastOnce import org.mockito.Mockito.isNull import org.mockito.Mockito.spy import org.mockito.Mockito.verify @@ -61,36 +63,83 @@ class UserFileManagerImplTest : SysuiTestCase() { UserFileManagerImpl(context, userManager, broadcastDispatcher, backgroundExecutor) } - @After - fun end() { - val dir = Environment.buildPath(context.filesDir, UserFileManagerImpl.ID) - dir.deleteRecursively() - } - @Test fun testGetFile() { assertThat(userFileManager.getFile(TEST_FILE_NAME, 0).path) .isEqualTo("${context.filesDir}/$TEST_FILE_NAME") assertThat(userFileManager.getFile(TEST_FILE_NAME, 11).path) - .isEqualTo("${context.filesDir}/${UserFileManagerImpl.ID}/11/files/$TEST_FILE_NAME") + .isEqualTo("${context.filesDir}/__USER_11_$TEST_FILE_NAME") } @Test fun testGetSharedPreferences() { + val primarySharedPref = userFileManager.getSharedPreferences(TEST_FILE_NAME, 0, 0) val secondarySharedPref = userFileManager.getSharedPreferences(TEST_FILE_NAME, 0, 11) - val secondaryUserDir = - Environment.buildPath( - context.filesDir, - UserFileManagerImpl.ID, - "11", + + assertThat(primarySharedPref).isNotEqualTo(secondarySharedPref) + + // Make sure these are different files + primarySharedPref.edit().putString("TEST", "ABC").commit() + assertThat(secondarySharedPref.getString("TEST", null)).isNull() + + context.deleteSharedPreferences("TEST") + context.deleteSharedPreferences("__USER_11_TEST") + } + + @Test + fun testMigrateFile() { + val userId = 12 + val fileName = "myFile.txt" + val fileContents = "TestingFile" + val legacyFile = + UserFileManagerImpl.createLegacyFile( + context, + UserFileManagerImpl.FILES, + fileName, + userId + )!! + + // Write file to legacy area + Files.createDirectories(legacyFile.getParentFile().toPath()) + Files.write(legacyFile.toPath(), fileContents.toByteArray()) + assertThat(legacyFile.exists()).isTrue() + + // getFile() should migrate the legacy file to the new location + val file = userFileManager.getFile(fileName, userId) + val newContents = String(Files.readAllBytes(file.toPath())) + + assertThat(newContents).isEqualTo(fileContents) + assertThat(legacyFile.exists()).isFalse() + assertThat(File(context.filesDir, UserFileManagerImpl.ROOT_DIR).exists()).isFalse() + } + + @Test + fun testMigrateSharedPrefs() { + val userId = 13 + val fileName = "myFile" + val contents = "TestingSharedPrefs" + val legacyFile = + UserFileManagerImpl.createLegacyFile( + context, UserFileManagerImpl.SHARED_PREFS, - TEST_FILE_NAME - ) + "$fileName.xml", + userId + )!! - assertThat(secondarySharedPref).isNotNull() - assertThat(secondaryUserDir.exists()) - assertThat(userFileManager.getSharedPreferences(TEST_FILE_NAME, 0, 0)) - .isNotEqualTo(secondarySharedPref) + // Write a valid shared prefs xml file to legacy area + val tmpPrefs = context.getSharedPreferences("tmp", Context.MODE_PRIVATE) + tmpPrefs.edit().putString(contents, contents).commit() + Files.createDirectories(legacyFile.getParentFile().toPath()) + val tmpFile = + Environment.buildPath(context.dataDir, UserFileManagerImpl.SHARED_PREFS, "tmp.xml") + tmpFile.renameTo(legacyFile) + assertThat(legacyFile.exists()).isTrue() + + // getSharedpreferences() should migrate the legacy file to the new location + val prefs = userFileManager.getSharedPreferences(fileName, Context.MODE_PRIVATE, userId) + assertThat(prefs.getString(contents, "")).isEqualTo(contents) + assertThat(legacyFile.exists()).isFalse() + assertThat(File(context.filesDir, UserFileManagerImpl.ROOT_DIR).exists()).isFalse() } @Test @@ -111,44 +160,14 @@ class UserFileManagerImplTest : SysuiTestCase() { @Test fun testClearDeletedUserData() { - val dir = Environment.buildPath(context.filesDir, UserFileManagerImpl.ID, "11", "files") - dir.mkdirs() - val file = - Environment.buildPath( - context.filesDir, - UserFileManagerImpl.ID, - "11", - "files", - TEST_FILE_NAME - ) - val secondaryUserDir = - Environment.buildPath( - context.filesDir, - UserFileManagerImpl.ID, - "11", - ) + val file = userFileManager.getFile(TEST_FILE_NAME, 11) file.createNewFile() - assertThat(secondaryUserDir.exists()).isTrue() + assertThat(file.exists()).isTrue() userFileManager.clearDeletedUserData() assertThat(backgroundExecutor.runAllReady()).isGreaterThan(0) - verify(userManager).aliveUsers - assertThat(secondaryUserDir.exists()).isFalse() - assertThat(file.exists()).isFalse() - } + verify(userManager, atLeastOnce()).aliveUsers - @Test - fun testEnsureParentDirExists() { - val file = - Environment.buildPath( - context.filesDir, - UserFileManagerImpl.ID, - "11", - "files", - TEST_FILE_NAME - ) - assertThat(file.parentFile.exists()).isFalse() - UserFileManagerImpl.ensureParentDirExists(file) - assertThat(file.parentFile.exists()).isTrue() + assertThat(file.exists()).isFalse() } } |