Add a persistence mechanism for panels' packages
This will allow to persist the packages of apps that provide device controls panels after they are authorized (opted in) by the user. Packages that are in the seeding list (config_controlsPreferredPackages) will be auto-added, but only when creating the set of authorized package for the first time (per user). Test: atest AuthorizedPanelsRepositoryImplTest Fixes: 264414289 Change-Id: Ic23e6172158bba3cf960e81919978ec62da79150
This commit is contained in:
@@ -34,6 +34,8 @@ import com.android.systemui.controls.management.ControlsListingController
|
|||||||
import com.android.systemui.controls.management.ControlsListingControllerImpl
|
import com.android.systemui.controls.management.ControlsListingControllerImpl
|
||||||
import com.android.systemui.controls.management.ControlsProviderSelectorActivity
|
import com.android.systemui.controls.management.ControlsProviderSelectorActivity
|
||||||
import com.android.systemui.controls.management.ControlsRequestDialog
|
import com.android.systemui.controls.management.ControlsRequestDialog
|
||||||
|
import com.android.systemui.controls.panels.AuthorizedPanelsRepository
|
||||||
|
import com.android.systemui.controls.panels.AuthorizedPanelsRepositoryImpl
|
||||||
import com.android.systemui.controls.settings.ControlsSettingsDialogManager
|
import com.android.systemui.controls.settings.ControlsSettingsDialogManager
|
||||||
import com.android.systemui.controls.settings.ControlsSettingsDialogManagerImpl
|
import com.android.systemui.controls.settings.ControlsSettingsDialogManagerImpl
|
||||||
import com.android.systemui.controls.ui.ControlActionCoordinator
|
import com.android.systemui.controls.ui.ControlActionCoordinator
|
||||||
@@ -104,6 +106,11 @@ abstract class ControlsModule {
|
|||||||
coordinator: ControlActionCoordinatorImpl
|
coordinator: ControlActionCoordinatorImpl
|
||||||
): ControlActionCoordinator
|
): ControlActionCoordinator
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
abstract fun provideAuthorizedPanelsRepository(
|
||||||
|
repository: AuthorizedPanelsRepositoryImpl
|
||||||
|
): AuthorizedPanelsRepository
|
||||||
|
|
||||||
@BindsOptionalOf
|
@BindsOptionalOf
|
||||||
abstract fun optionalPersistenceWrapper(): ControlsFavoritePersistenceWrapper
|
abstract fun optionalPersistenceWrapper(): ControlsFavoritePersistenceWrapper
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* 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.systemui.controls.panels
|
||||||
|
|
||||||
|
interface AuthorizedPanelsRepository {
|
||||||
|
fun getAuthorizedPanels(): Set<String>
|
||||||
|
|
||||||
|
fun addAuthorizedPanels(packageNames: Set<String>)
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
* 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.systemui.controls.panels
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.SharedPreferences
|
||||||
|
import com.android.systemui.R
|
||||||
|
import com.android.systemui.settings.UserFileManager
|
||||||
|
import com.android.systemui.settings.UserTracker
|
||||||
|
import com.android.systemui.statusbar.policy.DeviceControlsControllerImpl
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class AuthorizedPanelsRepositoryImpl
|
||||||
|
@Inject
|
||||||
|
constructor(
|
||||||
|
private val context: Context,
|
||||||
|
private val userFileManager: UserFileManager,
|
||||||
|
private val userTracker: UserTracker
|
||||||
|
) : AuthorizedPanelsRepository {
|
||||||
|
|
||||||
|
override fun getAuthorizedPanels(): Set<String> {
|
||||||
|
return getAuthorizedPanelsInternal(instantiateSharedPrefs())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun addAuthorizedPanels(packageNames: Set<String>) {
|
||||||
|
addAuthorizedPanelsInternal(instantiateSharedPrefs(), packageNames)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getAuthorizedPanelsInternal(sharedPreferences: SharedPreferences): Set<String> {
|
||||||
|
return sharedPreferences.getStringSet(KEY, emptySet())!!
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addAuthorizedPanelsInternal(
|
||||||
|
sharedPreferences: SharedPreferences,
|
||||||
|
packageNames: Set<String>
|
||||||
|
) {
|
||||||
|
val currentSet = getAuthorizedPanelsInternal(sharedPreferences)
|
||||||
|
sharedPreferences.edit().putStringSet(KEY, currentSet + packageNames).apply()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun instantiateSharedPrefs(): SharedPreferences {
|
||||||
|
val sharedPref =
|
||||||
|
userFileManager.getSharedPreferences(
|
||||||
|
DeviceControlsControllerImpl.PREFS_CONTROLS_FILE,
|
||||||
|
Context.MODE_PRIVATE,
|
||||||
|
userTracker.userId,
|
||||||
|
)
|
||||||
|
|
||||||
|
// If we've never run this (i.e., the key doesn't exist), add the default packages
|
||||||
|
if (sharedPref.getStringSet(KEY, null) == null) {
|
||||||
|
sharedPref
|
||||||
|
.edit()
|
||||||
|
.putStringSet(
|
||||||
|
KEY,
|
||||||
|
context.resources
|
||||||
|
.getStringArray(R.array.config_controlsPreferredPackages)
|
||||||
|
.toSet()
|
||||||
|
)
|
||||||
|
.apply()
|
||||||
|
}
|
||||||
|
return sharedPref
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val KEY = "authorized_panels"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,145 @@
|
|||||||
|
/*
|
||||||
|
* 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.systemui.controls.panels
|
||||||
|
|
||||||
|
import android.content.SharedPreferences
|
||||||
|
import android.testing.AndroidTestingRunner
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import com.android.systemui.R
|
||||||
|
import com.android.systemui.SysuiTestCase
|
||||||
|
import com.android.systemui.settings.UserFileManager
|
||||||
|
import com.android.systemui.settings.UserTracker
|
||||||
|
import com.android.systemui.util.FakeSharedPreferences
|
||||||
|
import com.android.systemui.util.mockito.whenever
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import java.io.File
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.mockito.Mock
|
||||||
|
import org.mockito.MockitoAnnotations
|
||||||
|
|
||||||
|
@RunWith(AndroidTestingRunner::class)
|
||||||
|
@SmallTest
|
||||||
|
class AuthorizedPanelsRepositoryImplTest : SysuiTestCase() {
|
||||||
|
|
||||||
|
@Mock private lateinit var userTracker: UserTracker
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this)
|
||||||
|
mContext.orCreateTestableResources.addOverride(
|
||||||
|
R.array.config_controlsPreferredPackages,
|
||||||
|
arrayOf<String>()
|
||||||
|
)
|
||||||
|
whenever(userTracker.userId).thenReturn(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testPreApprovedPackagesAreSeededIfNoSavedPreferences() {
|
||||||
|
mContext.orCreateTestableResources.addOverride(
|
||||||
|
R.array.config_controlsPreferredPackages,
|
||||||
|
arrayOf(TEST_PACKAGE)
|
||||||
|
)
|
||||||
|
val sharedPrefs = FakeSharedPreferences()
|
||||||
|
val fileManager = FakeUserFileManager(mapOf(0 to sharedPrefs))
|
||||||
|
val repository = createRepository(fileManager)
|
||||||
|
|
||||||
|
assertThat(repository.getAuthorizedPanels()).containsExactly(TEST_PACKAGE)
|
||||||
|
assertThat(sharedPrefs.getStringSet(KEY, null)).containsExactly(TEST_PACKAGE)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testPreApprovedPackagesNotSeededIfEmptySavedPreferences() {
|
||||||
|
mContext.orCreateTestableResources.addOverride(
|
||||||
|
R.array.config_controlsPreferredPackages,
|
||||||
|
arrayOf(TEST_PACKAGE)
|
||||||
|
)
|
||||||
|
val sharedPrefs = FakeSharedPreferences()
|
||||||
|
sharedPrefs.edit().putStringSet(KEY, emptySet()).apply()
|
||||||
|
val fileManager = FakeUserFileManager(mapOf(0 to sharedPrefs))
|
||||||
|
createRepository(fileManager)
|
||||||
|
|
||||||
|
assertThat(sharedPrefs.getStringSet(KEY, null)).isEmpty()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testPreApprovedPackagesOnlySetForUserThatDoesntHaveThem() {
|
||||||
|
mContext.orCreateTestableResources.addOverride(
|
||||||
|
R.array.config_controlsPreferredPackages,
|
||||||
|
arrayOf(TEST_PACKAGE)
|
||||||
|
)
|
||||||
|
val sharedPrefs_0 = FakeSharedPreferences()
|
||||||
|
val sharedPrefs_1 = FakeSharedPreferences()
|
||||||
|
sharedPrefs_1.edit().putStringSet(KEY, emptySet()).apply()
|
||||||
|
val fileManager = FakeUserFileManager(mapOf(0 to sharedPrefs_0, 1 to sharedPrefs_1))
|
||||||
|
val repository = createRepository(fileManager)
|
||||||
|
|
||||||
|
assertThat(repository.getAuthorizedPanels()).containsExactly(TEST_PACKAGE)
|
||||||
|
whenever(userTracker.userId).thenReturn(1)
|
||||||
|
assertThat(repository.getAuthorizedPanels()).isEmpty()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testGetAuthorizedPackages() {
|
||||||
|
val sharedPrefs = FakeSharedPreferences()
|
||||||
|
sharedPrefs.edit().putStringSet(KEY, mutableSetOf(TEST_PACKAGE)).apply()
|
||||||
|
val fileManager = FakeUserFileManager(mapOf(0 to sharedPrefs))
|
||||||
|
|
||||||
|
val repository = createRepository(fileManager)
|
||||||
|
assertThat(repository.getAuthorizedPanels()).containsExactly(TEST_PACKAGE)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testSetAuthorizedPackage() {
|
||||||
|
val sharedPrefs = FakeSharedPreferences()
|
||||||
|
val fileManager = FakeUserFileManager(mapOf(0 to sharedPrefs))
|
||||||
|
|
||||||
|
val repository = createRepository(fileManager)
|
||||||
|
repository.addAuthorizedPanels(setOf(TEST_PACKAGE))
|
||||||
|
assertThat(sharedPrefs.getStringSet(KEY, null)).containsExactly(TEST_PACKAGE)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createRepository(userFileManager: UserFileManager): AuthorizedPanelsRepositoryImpl {
|
||||||
|
return AuthorizedPanelsRepositoryImpl(mContext, userFileManager, userTracker)
|
||||||
|
}
|
||||||
|
|
||||||
|
private class FakeUserFileManager(private val sharedPrefs: Map<Int, SharedPreferences>) :
|
||||||
|
UserFileManager {
|
||||||
|
override fun getFile(fileName: String, userId: Int): File {
|
||||||
|
throw UnsupportedOperationException()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getSharedPreferences(
|
||||||
|
fileName: String,
|
||||||
|
mode: Int,
|
||||||
|
userId: Int
|
||||||
|
): SharedPreferences {
|
||||||
|
if (fileName != FILE_NAME) {
|
||||||
|
throw IllegalArgumentException("Preference files must be $FILE_NAME")
|
||||||
|
}
|
||||||
|
return sharedPrefs.getValue(userId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val FILE_NAME = "controls_prefs"
|
||||||
|
private const val KEY = "authorized_panels"
|
||||||
|
private const val TEST_PACKAGE = "package"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -41,7 +41,7 @@ class FakeSharedPreferences : SharedPreferences {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun getStringSet(key: String, defValues: MutableSet<String>?): MutableSet<String>? {
|
override fun getStringSet(key: String, defValues: MutableSet<String>?): MutableSet<String>? {
|
||||||
return data.getOrDefault(key, defValues) as? MutableSet<String>?
|
return (data.getOrDefault(key, defValues) as? Set<String>?)?.toMutableSet()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getInt(key: String, defValue: Int): Int {
|
override fun getInt(key: String, defValue: Int): Int {
|
||||||
|
|||||||
Reference in New Issue
Block a user