diff --git a/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt b/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt index 6d6410de1a91d..6af8e73c8d254 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt @@ -34,6 +34,8 @@ import com.android.systemui.controls.management.ControlsListingController import com.android.systemui.controls.management.ControlsListingControllerImpl import com.android.systemui.controls.management.ControlsProviderSelectorActivity 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.ControlsSettingsDialogManagerImpl import com.android.systemui.controls.ui.ControlActionCoordinator @@ -104,6 +106,11 @@ abstract class ControlsModule { coordinator: ControlActionCoordinatorImpl ): ControlActionCoordinator + @Binds + abstract fun provideAuthorizedPanelsRepository( + repository: AuthorizedPanelsRepositoryImpl + ): AuthorizedPanelsRepository + @BindsOptionalOf abstract fun optionalPersistenceWrapper(): ControlsFavoritePersistenceWrapper diff --git a/packages/SystemUI/src/com/android/systemui/controls/panels/AuthorizedPanelsRepository.kt b/packages/SystemUI/src/com/android/systemui/controls/panels/AuthorizedPanelsRepository.kt new file mode 100644 index 0000000000000..1a6b84a8e0541 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/controls/panels/AuthorizedPanelsRepository.kt @@ -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 + + fun addAuthorizedPanels(packageNames: Set) +} diff --git a/packages/SystemUI/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryImpl.kt new file mode 100644 index 0000000000000..f7e43a77b5739 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryImpl.kt @@ -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 { + return getAuthorizedPanelsInternal(instantiateSharedPrefs()) + } + + override fun addAuthorizedPanels(packageNames: Set) { + addAuthorizedPanelsInternal(instantiateSharedPrefs(), packageNames) + } + + private fun getAuthorizedPanelsInternal(sharedPreferences: SharedPreferences): Set { + return sharedPreferences.getStringSet(KEY, emptySet())!! + } + + private fun addAuthorizedPanelsInternal( + sharedPreferences: SharedPreferences, + packageNames: Set + ) { + 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" + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryImplTest.kt new file mode 100644 index 0000000000000..b91a3fd4b28cb --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryImplTest.kt @@ -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() + ) + 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) : + 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" + } +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/util/FakeSharedPreferences.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/util/FakeSharedPreferences.kt index 4a881a7ce8987..fd1b8e9ebb7a5 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/util/FakeSharedPreferences.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/FakeSharedPreferences.kt @@ -41,7 +41,7 @@ class FakeSharedPreferences : SharedPreferences { } override fun getStringSet(key: String, defValues: MutableSet?): MutableSet? { - return data.getOrDefault(key, defValues) as? MutableSet? + return (data.getOrDefault(key, defValues) as? Set?)?.toMutableSet() } override fun getInt(key: String, defValue: Int): Int {