diff options
9 files changed, 336 insertions, 20 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/QSPreferencesRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/QSPreferencesRepository.kt new file mode 100644 index 000000000000..f3e5b8f0c214 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/QSPreferencesRepository.kt @@ -0,0 +1,73 @@ +/* + * 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.qs.panels.data.repository + +import android.content.Context +import android.content.SharedPreferences +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Background +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.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.map + +/** Repository for QS user preferences. */ +@OptIn(ExperimentalCoroutinesApi::class) +@SysUISingleton +class QSPreferencesRepository +@Inject +constructor( + private val userFileManager: UserFileManager, + private val userRepository: UserRepository, + @Background private val backgroundDispatcher: CoroutineDispatcher, +) { + /** Whether to show the labels on icon tiles for the current user. */ + val showLabels: Flow<Boolean> = + userRepository.selectedUserInfo + .flatMapLatest { userInfo -> + val prefs = getSharedPrefs(userInfo.id) + prefs.observe().emitOnStart().map { prefs.getBoolean(ICON_LABELS_KEY, false) } + } + .flowOn(backgroundDispatcher) + + /** Sets for the current user whether to show the labels on icon tiles. */ + fun setShowLabels(showLabels: Boolean) { + with(getSharedPrefs(userRepository.getSelectedUserInfo().id)) { + edit().putBoolean(ICON_LABELS_KEY, showLabels).apply() + } + } + + private fun getSharedPrefs(userId: Int): SharedPreferences { + return userFileManager.getSharedPreferences( + FILE_NAME, + Context.MODE_PRIVATE, + userId, + ) + } + + companion object { + private const val ICON_LABELS_KEY = "show_icon_labels" + const val FILE_NAME = "quick_settings_prefs" + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/IconLabelVisibilityInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/IconLabelVisibilityInteractor.kt index a871531f283a..6a899b07b2a0 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/IconLabelVisibilityInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/IconLabelVisibilityInteractor.kt @@ -20,7 +20,6 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.log.LogBuffer import com.android.systemui.log.core.LogLevel -import com.android.systemui.qs.panels.data.repository.IconLabelVisibilityRepository import com.android.systemui.qs.panels.shared.model.IconLabelVisibilityLog import javax.inject.Inject import kotlinx.coroutines.CoroutineScope @@ -33,17 +32,17 @@ import kotlinx.coroutines.flow.stateIn class IconLabelVisibilityInteractor @Inject constructor( - private val repo: IconLabelVisibilityRepository, + private val preferencesInteractor: QSPreferencesInteractor, @IconLabelVisibilityLog private val logBuffer: LogBuffer, @Application scope: CoroutineScope, ) { val showLabels: StateFlow<Boolean> = - repo.showLabels + preferencesInteractor.showLabels .onEach { logChange(it) } - .stateIn(scope, SharingStarted.WhileSubscribed(), repo.showLabels.value) + .stateIn(scope, SharingStarted.WhileSubscribed(), false) fun setShowLabels(showLabels: Boolean) { - repo.setShowLabels(showLabels) + preferencesInteractor.setShowLabels(showLabels) } private fun logChange(showLabels: Boolean) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/IconLabelVisibilityRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/QSPreferencesInteractor.kt index 686e5f49442b..811be80d23fa 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/IconLabelVisibilityRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/QSPreferencesInteractor.kt @@ -14,22 +14,18 @@ * limitations under the License. */ -package com.android.systemui.qs.panels.data.repository +package com.android.systemui.qs.panels.domain.interactor import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.qs.panels.data.repository.QSPreferencesRepository import javax.inject.Inject -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.Flow -/** Repository for whether to show the labels of icon tiles. */ @SysUISingleton -class IconLabelVisibilityRepository @Inject constructor() { - // TODO(b/341735914): Persist and back up showLabels - private val _showLabels = MutableStateFlow(false) - val showLabels: StateFlow<Boolean> = _showLabels.asStateFlow() +class QSPreferencesInteractor @Inject constructor(private val repo: QSPreferencesRepository) { + val showLabels: Flow<Boolean> = repo.showLabels fun setShowLabels(showLabels: Boolean) { - _showLabels.value = showLabels + repo.setShowLabels(showLabels) } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/IconLabelVisibilityViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/IconLabelVisibilityViewModel.kt index 5d4b8f1773f2..12cbde2cbc91 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/IconLabelVisibilityViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/IconLabelVisibilityViewModel.kt @@ -30,7 +30,9 @@ interface IconLabelVisibilityViewModel { @SysUISingleton class IconLabelVisibilityViewModelImpl @Inject -constructor(private val interactor: IconLabelVisibilityInteractor) : IconLabelVisibilityViewModel { +constructor( + private val interactor: IconLabelVisibilityInteractor, +) : IconLabelVisibilityViewModel { override val showLabels: StateFlow<Boolean> = interactor.showLabels override fun setShowLabels(showLabels: Boolean) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/panels/data/QSPreferencesRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/panels/data/QSPreferencesRepositoryTest.kt new file mode 100644 index 000000000000..b0aa6ddf44ce --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/panels/data/QSPreferencesRepositoryTest.kt @@ -0,0 +1,130 @@ +/* + * 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.qs.panels.data + +import android.content.Context +import android.content.SharedPreferences +import android.content.pm.UserInfo +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.kosmos.testScope +import com.android.systemui.qs.panels.data.repository.QSPreferencesRepository +import com.android.systemui.qs.panels.data.repository.qsPreferencesRepository +import com.android.systemui.settings.userFileManager +import com.android.systemui.testKosmos +import com.android.systemui.user.data.repository.fakeUserRepository +import com.android.systemui.user.data.repository.userRepository +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.test.runTest +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidTestingRunner::class) +class QSPreferencesRepositoryTest : SysuiTestCase() { + private val kosmos = testKosmos() + private val underTest = with(kosmos) { qsPreferencesRepository } + + @Test + fun showLabels_updatesFromSharedPreferences() = + with(kosmos) { + testScope.runTest { + val latest by collectLastValue(underTest.showLabels) + assertThat(latest).isFalse() + + setShowLabelsInSharedPreferences(true) + assertThat(latest).isTrue() + + setShowLabelsInSharedPreferences(false) + assertThat(latest).isFalse() + } + } + + @Test + fun showLabels_updatesFromUserChange() = + with(kosmos) { + testScope.runTest { + fakeUserRepository.setUserInfos(USERS) + val latest by collectLastValue(underTest.showLabels) + + fakeUserRepository.setSelectedUserInfo(PRIMARY_USER) + setShowLabelsInSharedPreferences(false) + + fakeUserRepository.setSelectedUserInfo(ANOTHER_USER) + setShowLabelsInSharedPreferences(true) + + fakeUserRepository.setSelectedUserInfo(PRIMARY_USER) + assertThat(latest).isFalse() + } + } + + @Test + fun setShowLabels_inSharedPreferences() { + underTest.setShowLabels(false) + assertThat(getShowLabelsFromSharedPreferences(true)).isFalse() + + underTest.setShowLabels(true) + assertThat(getShowLabelsFromSharedPreferences(false)).isTrue() + } + + @Test + fun setShowLabels_forDifferentUser() = + with(kosmos) { + testScope.runTest { + fakeUserRepository.setUserInfos(USERS) + + fakeUserRepository.setSelectedUserInfo(PRIMARY_USER) + underTest.setShowLabels(false) + assertThat(getShowLabelsFromSharedPreferences(true)).isFalse() + + fakeUserRepository.setSelectedUserInfo(ANOTHER_USER) + underTest.setShowLabels(true) + assertThat(getShowLabelsFromSharedPreferences(false)).isTrue() + + fakeUserRepository.setSelectedUserInfo(PRIMARY_USER) + assertThat(getShowLabelsFromSharedPreferences(true)).isFalse() + } + } + + private fun getSharedPreferences(): SharedPreferences = + with(kosmos) { + return userFileManager.getSharedPreferences( + QSPreferencesRepository.FILE_NAME, + Context.MODE_PRIVATE, + userRepository.getSelectedUserInfo().id, + ) + } + + private fun setShowLabelsInSharedPreferences(value: Boolean) { + getSharedPreferences().edit().putBoolean(ICON_LABELS_KEY, value).apply() + } + + private fun getShowLabelsFromSharedPreferences(defaultValue: Boolean): Boolean { + return getSharedPreferences().getBoolean(ICON_LABELS_KEY, defaultValue) + } + + companion object { + private const val ICON_LABELS_KEY = "show_icon_labels" + private const val PRIMARY_USER_ID = 0 + private val PRIMARY_USER = UserInfo(PRIMARY_USER_ID, "user 0", UserInfo.FLAG_MAIN) + private const val ANOTHER_USER_ID = 1 + private val ANOTHER_USER = UserInfo(ANOTHER_USER_ID, "user 1", UserInfo.FLAG_FULL) + private val USERS = listOf(PRIMARY_USER, ANOTHER_USER) + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/panels/domain/interactor/IconLabelVisibilityInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/panels/domain/interactor/IconLabelVisibilityInteractorTest.kt new file mode 100644 index 000000000000..9b08432e290f --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/panels/domain/interactor/IconLabelVisibilityInteractorTest.kt @@ -0,0 +1,90 @@ +/* + * 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.qs.panels.domain.interactor + +import android.content.pm.UserInfo +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.kosmos.testScope +import com.android.systemui.testKosmos +import com.android.systemui.user.data.repository.fakeUserRepository +import com.google.common.truth.Truth.assertThat +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 + +@OptIn(ExperimentalCoroutinesApi::class) +@SmallTest +@RunWith(AndroidTestingRunner::class) +class IconLabelVisibilityInteractorTest : SysuiTestCase() { + private val kosmos = testKosmos() + private val underTest = with(kosmos) { iconLabelVisibilityInteractor } + + @Before + fun setUp() { + with(kosmos) { fakeUserRepository.setUserInfos(USERS) } + } + + @Test + fun changingShowLabels_receivesCorrectShowLabels() = + with(kosmos) { + testScope.runTest { + val showLabels by collectLastValue(underTest.showLabels) + + underTest.setShowLabels(false) + runCurrent() + assertThat(showLabels).isFalse() + + underTest.setShowLabels(true) + runCurrent() + assertThat(showLabels).isTrue() + } + } + + @Test + fun changingUser_receivesCorrectShowLabels() = + with(kosmos) { + testScope.runTest { + val showLabels by collectLastValue(underTest.showLabels) + + fakeUserRepository.setSelectedUserInfo(PRIMARY_USER) + underTest.setShowLabels(false) + runCurrent() + assertThat(showLabels).isFalse() + + fakeUserRepository.setSelectedUserInfo(ANOTHER_USER) + underTest.setShowLabels(true) + runCurrent() + assertThat(showLabels).isTrue() + + fakeUserRepository.setSelectedUserInfo(PRIMARY_USER) + runCurrent() + assertThat(showLabels).isFalse() + } + } + + companion object { + private val PRIMARY_USER = UserInfo(0, "user 0", UserInfo.FLAG_MAIN) + private val ANOTHER_USER = UserInfo(1, "user 1", UserInfo.FLAG_FULL) + private val USERS = listOf(PRIMARY_USER, ANOTHER_USER) + } +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/QSPreferencesRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/QSPreferencesRepositoryKosmos.kt new file mode 100644 index 000000000000..39ae5eb44c65 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/QSPreferencesRepositoryKosmos.kt @@ -0,0 +1,25 @@ +/* + * 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.qs.panels.data.repository + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.testDispatcher +import com.android.systemui.settings.userFileManager +import com.android.systemui.user.data.repository.userRepository + +val Kosmos.qsPreferencesRepository by + Kosmos.Fixture { QSPreferencesRepository(userFileManager, userRepository, testDispatcher) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/IconLabelVisibilityInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/IconLabelVisibilityInteractorKosmos.kt index 7b9e4a17e998..954084b874a0 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/IconLabelVisibilityInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/IconLabelVisibilityInteractorKosmos.kt @@ -19,12 +19,11 @@ package com.android.systemui.qs.panels.domain.interactor import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.log.core.FakeLogBuffer -import com.android.systemui.qs.panels.data.repository.iconLabelVisibilityRepository val Kosmos.iconLabelVisibilityInteractor by Kosmos.Fixture { IconLabelVisibilityInteractor( - iconLabelVisibilityRepository, + qsPreferencesInteractor, FakeLogBuffer.Factory.create(), applicationCoroutineScope ) diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/IconLabelVisibilityRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/QSPreferencesInteractorKosmos.kt index 277dbb7016ad..eb83e325d79b 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/IconLabelVisibilityRepositoryKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/QSPreferencesInteractorKosmos.kt @@ -14,8 +14,10 @@ * limitations under the License. */ -package com.android.systemui.qs.panels.data.repository +package com.android.systemui.qs.panels.domain.interactor import com.android.systemui.kosmos.Kosmos +import com.android.systemui.qs.panels.data.repository.qsPreferencesRepository -val Kosmos.iconLabelVisibilityRepository by Kosmos.Fixture { IconLabelVisibilityRepository() } +val Kosmos.qsPreferencesInteractor by + Kosmos.Fixture { QSPreferencesInteractor(qsPreferencesRepository) } |