Read and write auto on toggle value.
Test: atest -c com.android.systemui.qs.tiles.dialog.bluetooth
Bug: b/316822488 b/316985153
Flag: ACONFIG com.android.settingslib.flags.bluetooth_qs_tile_dialog_auto_on_toggle DISABLED
Change-Id: I2e87eb596e1433a70dd6ac46ee98bd63ed4881f8
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothAutoOnInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothAutoOnInteractor.kt
new file mode 100644
index 0000000..dcae088
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothAutoOnInteractor.kt
@@ -0,0 +1,61 @@
+/*
+ * 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.tiles.dialog.bluetooth
+
+import android.util.Log
+import com.android.systemui.dagger.SysUISingleton
+import javax.inject.Inject
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.map
+
+/** Interactor class responsible for interacting with the Bluetooth Auto-On feature. */
+@SysUISingleton
+class BluetoothAutoOnInteractor
+@Inject
+constructor(
+ private val bluetoothAutoOnRepository: BluetoothAutoOnRepository,
+) {
+
+ val isEnabled = bluetoothAutoOnRepository.getValue.map { it == ENABLED }.distinctUntilChanged()
+
+ /**
+ * Checks if the auto on value is present in the repository.
+ *
+ * @return `true` if a value is present (i.e, the feature is enabled by the Bluetooth server).
+ */
+ suspend fun isValuePresent(): Boolean = bluetoothAutoOnRepository.isValuePresent()
+
+ /**
+ * Sets enabled or disabled based on the provided value.
+ *
+ * @param value `true` to enable the feature, `false` to disable it.
+ */
+ suspend fun setEnabled(value: Boolean) {
+ if (!isValuePresent()) {
+ Log.e(TAG, "Trying to set toggle value while feature not available.")
+ } else {
+ val newValue = if (value) ENABLED else DISABLED
+ bluetoothAutoOnRepository.setValue(newValue)
+ }
+ }
+
+ companion object {
+ private const val TAG = "BluetoothAutoOnInteractor"
+ const val DISABLED = 0
+ const val ENABLED = 1
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothAutoOnRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothAutoOnRepository.kt
new file mode 100644
index 0000000..e17b4d3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothAutoOnRepository.kt
@@ -0,0 +1,101 @@
+/*
+ * 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.qs.tiles.dialog.bluetooth
+
+import android.os.UserHandle
+import android.util.Log
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.user.data.repository.UserRepository
+import com.android.systemui.util.settings.SecureSettings
+import com.android.systemui.util.settings.SettingsProxyExt.observerFlow
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.flow.shareIn
+import kotlinx.coroutines.withContext
+
+/** Repository class responsible for managing the Bluetooth Auto-On feature settings. */
+// TODO(b/316822488): Handle multi-user
+@SysUISingleton
+class BluetoothAutoOnRepository
+@Inject
+constructor(
+ private val secureSettings: SecureSettings,
+ private val userRepository: UserRepository,
+ @Application private val coroutineScope: CoroutineScope,
+ @Background private val backgroundDispatcher: CoroutineDispatcher,
+) {
+ // Flow representing the auto on setting value
+ internal val getValue: Flow<Int> =
+ secureSettings
+ .observerFlow(UserHandle.USER_SYSTEM, SETTING_NAME)
+ .onStart { emit(Unit) }
+ .map {
+ if (userRepository.getSelectedUserInfo().id != UserHandle.USER_SYSTEM) {
+ Log.i(TAG, "Current user is not USER_SYSTEM. Multi-user is not supported")
+ return@map UNSET
+ }
+ secureSettings.getIntForUser(SETTING_NAME, UNSET, UserHandle.USER_SYSTEM)
+ }
+ .distinctUntilChanged()
+ .flowOn(backgroundDispatcher)
+ .shareIn(coroutineScope, SharingStarted.WhileSubscribed(replayExpirationMillis = 0))
+
+ /**
+ * Checks if the auto on setting value is ever set for the current user.
+ *
+ * @return `true` if the setting value is not UNSET, `false` otherwise.
+ */
+ suspend fun isValuePresent(): Boolean =
+ withContext(backgroundDispatcher) {
+ if (userRepository.getSelectedUserInfo().id != UserHandle.USER_SYSTEM) {
+ Log.i(TAG, "Current user is not USER_SYSTEM. Multi-user is not supported")
+ false
+ } else {
+ secureSettings.getIntForUser(SETTING_NAME, UNSET, UserHandle.USER_SYSTEM) != UNSET
+ }
+ }
+
+ /**
+ * Sets the Bluetooth Auto-On setting value for the current user.
+ *
+ * @param value The new setting value to be applied.
+ */
+ suspend fun setValue(value: Int) {
+ withContext(backgroundDispatcher) {
+ if (userRepository.getSelectedUserInfo().id != UserHandle.USER_SYSTEM) {
+ Log.i(TAG, "Current user is not USER_SYSTEM. Multi-user is not supported")
+ } else {
+ secureSettings.putIntForUser(SETTING_NAME, value, UserHandle.USER_SYSTEM)
+ }
+ }
+ }
+
+ companion object {
+ private const val TAG = "BluetoothAutoOnRepository"
+ const val SETTING_NAME = "bluetooth_automatic_turn_on"
+ const val UNSET = -1
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialog.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialog.kt
index 0cedba33..6b53c7a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialog.kt
@@ -71,6 +71,10 @@
internal val bluetoothStateToggle
get() = mutableBluetoothStateToggle.asStateFlow()
+ private val mutableBluetoothAutoOnToggle: MutableStateFlow<Boolean?> = MutableStateFlow(null)
+ internal val bluetoothAutoOnToggle
+ get() = mutableBluetoothAutoOnToggle.asStateFlow()
+
private val mutableDeviceItemClick: MutableSharedFlow<DeviceItem> =
MutableSharedFlow(extraBufferCapacity = 1)
internal val deviceItemClick
@@ -89,6 +93,7 @@
private lateinit var toggleView: Switch
private lateinit var subtitleTextView: TextView
+ private lateinit var autoOnToggle: Switch
private lateinit var autoOnToggleView: View
private lateinit var doneButton: View
private lateinit var seeAllButton: View
@@ -109,6 +114,7 @@
toggleView = requireViewById(R.id.bluetooth_toggle)
subtitleTextView = requireViewById(R.id.bluetooth_tile_dialog_subtitle) as TextView
+ autoOnToggle = requireViewById(R.id.bluetooth_auto_on_toggle)
autoOnToggleView = requireViewById(R.id.bluetooth_auto_on_toggle_layout)
doneButton = requireViewById(R.id.done_button)
seeAllButton = requireViewById(R.id.see_all_button)
@@ -195,6 +201,16 @@
autoOnToggleView.visibility = uiProperties.autoOnToggleVisibility
}
+ internal fun onBluetoothAutoOnUpdated(isEnabled: Boolean) {
+ if (::autoOnToggle.isInitialized) {
+ autoOnToggle.apply {
+ isChecked = isEnabled
+ setEnabled(true)
+ alpha = ENABLED_ALPHA
+ }
+ }
+ }
+
private fun setupToggle() {
toggleView.isChecked = bluetoothToggleInitialValue
toggleView.setOnCheckedChangeListener { view, isChecked ->
@@ -208,6 +224,14 @@
}
autoOnToggleView.visibility = initialUiProperties.autoOnToggleVisibility
+ autoOnToggle.setOnCheckedChangeListener { view, isChecked ->
+ mutableBluetoothAutoOnToggle.value = isChecked
+ view.apply {
+ isEnabled = false
+ alpha = DISABLED_ALPHA
+ }
+ uiEventLogger.log(BluetoothTileDialogUiEvent.BLUETOOTH_AUTO_ON_TOGGLE_CLICKED)
+ }
}
private fun setupRecyclerView() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogUiEvent.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogUiEvent.kt
index 86e5dde..cd52e0d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogUiEvent.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogUiEvent.kt
@@ -31,7 +31,8 @@
@UiEvent(doc = "Saved clicked to connect") SAVED_DEVICE_CONNECT(1500),
@UiEvent(doc = "Active device clicked to disconnect") ACTIVE_DEVICE_DISCONNECT(1507),
@UiEvent(doc = "Connected other device clicked to disconnect")
- CONNECTED_OTHER_DEVICE_DISCONNECT(1508);
+ CONNECTED_OTHER_DEVICE_DISCONNECT(1508),
+ @UiEvent(doc = "The auto on toggle is clicked") BLUETOOTH_AUTO_ON_TOGGLE_CLICKED(1617);
override fun getId() = metricId
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModel.kt
index 573ac5e..5a14e5f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModel.kt
@@ -26,6 +26,7 @@
import android.view.ViewGroup
import androidx.annotation.DimenRes
import androidx.annotation.StringRes
+import androidx.annotation.VisibleForTesting
import com.android.internal.jank.InteractionJankMonitor
import com.android.internal.logging.UiEventLogger
import com.android.settingslib.flags.Flags.bluetoothQsTileDialogAutoOnToggle
@@ -63,6 +64,7 @@
constructor(
private val deviceItemInteractor: DeviceItemInteractor,
private val bluetoothStateInteractor: BluetoothStateInteractor,
+ private val bluetoothAutoOnInteractor: BluetoothAutoOnInteractor,
private val dialogTransitionAnimator: DialogTransitionAnimator,
private val activityStarter: ActivityStarter,
private val systemClock: SystemClock,
@@ -148,7 +150,10 @@
bluetoothStateInteractor.bluetoothStateUpdate
.filterNotNull()
.onEach {
- dialog.onBluetoothStateUpdated(it, UiProperties.build(it))
+ dialog.onBluetoothStateUpdated(
+ it,
+ UiProperties.build(it, isAutoOnToggleFeatureAvailable())
+ )
updateDeviceItemJob?.cancel()
updateDeviceItemJob = launch {
deviceItemInteractor.updateDeviceItems(
@@ -182,6 +187,21 @@
}
.launchIn(this)
+ if (isAutoOnToggleFeatureAvailable()) {
+ // bluetoothAutoOnUpdate is emitted when bluetooth auto on on/off state is
+ // changed.
+ bluetoothAutoOnInteractor.isEnabled
+ .onEach { dialog.onBluetoothAutoOnUpdated(it) }
+ .launchIn(this)
+
+ // bluetoothAutoOnToggle is emitted when user toggles the bluetooth auto on
+ // switch, send the new value to the bluetoothAutoOnInteractor.
+ dialog.bluetoothAutoOnToggle
+ .filterNotNull()
+ .onEach { bluetoothAutoOnInteractor.setEnabled(it) }
+ .launchIn(this)
+ }
+
produce<Unit> { awaitClose { dialog.cancel() } }
}
}
@@ -197,7 +217,10 @@
return BluetoothTileDialog(
bluetoothStateInteractor.isBluetoothEnabled,
- UiProperties.build(bluetoothStateInteractor.isBluetoothEnabled),
+ UiProperties.build(
+ bluetoothStateInteractor.isBluetoothEnabled,
+ isAutoOnToggleFeatureAvailable()
+ ),
cachedContentHeight,
this@BluetoothTileDialogViewModel,
mainDispatcher,
@@ -249,6 +272,10 @@
}
}
+ @VisibleForTesting
+ internal suspend fun isAutoOnToggleFeatureAvailable() =
+ bluetoothQsTileDialogAutoOnToggle() && bluetoothAutoOnInteractor.isValuePresent()
+
companion object {
private const val INTERACTION_JANK_TAG = "bluetooth_tile_dialog"
private const val CONTENT_HEIGHT_PREF_KEY = Prefs.Key.BLUETOOTH_TILE_DIALOG_CONTENT_HEIGHT
@@ -263,14 +290,17 @@
@DimenRes val scrollViewMinHeightResId: Int,
) {
companion object {
- internal fun build(isBluetoothEnabled: Boolean) =
+ internal fun build(
+ isBluetoothEnabled: Boolean,
+ isAutoOnToggleFeatureAvailable: Boolean
+ ) =
UiProperties(
subTitleResId = getSubtitleResId(isBluetoothEnabled),
autoOnToggleVisibility =
- if (bluetoothQsTileDialogAutoOnToggle() && !isBluetoothEnabled) VISIBLE
+ if (isAutoOnToggleFeatureAvailable && !isBluetoothEnabled) VISIBLE
else GONE,
scrollViewMinHeightResId =
- if (bluetoothQsTileDialogAutoOnToggle())
+ if (isAutoOnToggleFeatureAvailable)
R.dimen.bluetooth_dialog_scroll_view_min_height_with_auto_on
else R.dimen.bluetooth_dialog_scroll_view_min_height
)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothAutoOnInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothAutoOnInteractorTest.kt
new file mode 100644
index 0000000..3710713
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothAutoOnInteractorTest.kt
@@ -0,0 +1,98 @@
+/*
+ * 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.tiles.dialog.bluetooth
+
+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.user.data.repository.FakeUserRepository
+import com.android.systemui.util.settings.FakeSettings
+import com.google.common.truth.Truth
+import kotlin.test.Test
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Rule
+import org.junit.runner.RunWith
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class BluetoothAutoOnInteractorTest : SysuiTestCase() {
+ @get:Rule val mockitoRule: MockitoRule = MockitoJUnit.rule()
+ private val testDispatcher = StandardTestDispatcher()
+ private val testScope = TestScope(testDispatcher)
+ private var secureSettings: FakeSettings = FakeSettings()
+ private val userRepository: FakeUserRepository = FakeUserRepository()
+ private lateinit var bluetoothAutoOnInteractor: BluetoothAutoOnInteractor
+
+ @Before
+ fun setUp() {
+ bluetoothAutoOnInteractor =
+ BluetoothAutoOnInteractor(
+ BluetoothAutoOnRepository(
+ secureSettings,
+ userRepository,
+ testScope.backgroundScope,
+ testDispatcher
+ )
+ )
+ }
+
+ @Test
+ fun testSet_bluetoothAutoOnUnset_doNothing() {
+ testScope.runTest {
+ bluetoothAutoOnInteractor.setEnabled(true)
+
+ val actualValue by collectLastValue(bluetoothAutoOnInteractor.isEnabled)
+
+ runCurrent()
+
+ Truth.assertThat(actualValue).isEqualTo(false)
+ }
+ }
+
+ @Test
+ fun testSet_bluetoothAutoOnSet_setNewValue() {
+ testScope.runTest {
+ userRepository.setUserInfos(listOf(SYSTEM_USER))
+ secureSettings.putIntForUser(
+ BluetoothAutoOnRepository.SETTING_NAME,
+ BluetoothAutoOnInteractor.DISABLED,
+ SYSTEM_USER_ID
+ )
+ bluetoothAutoOnInteractor.setEnabled(true)
+
+ val actualValue by collectLastValue(bluetoothAutoOnInteractor.isEnabled)
+
+ runCurrent()
+
+ Truth.assertThat(actualValue).isEqualTo(true)
+ }
+ }
+
+ companion object {
+ private const val SYSTEM_USER_ID = 0
+ private val SYSTEM_USER =
+ UserInfo(/* id= */ SYSTEM_USER_ID, /* name= */ "system user", /* flags= */ 0)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothAutoOnRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothAutoOnRepositoryTest.kt
new file mode 100644
index 0000000..8986d99
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothAutoOnRepositoryTest.kt
@@ -0,0 +1,127 @@
+/*
+ * 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.tiles.dialog.bluetooth
+
+import android.content.pm.UserInfo
+import android.os.UserHandle
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.qs.tiles.dialog.bluetooth.BluetoothAutoOnInteractor.Companion.DISABLED
+import com.android.systemui.qs.tiles.dialog.bluetooth.BluetoothAutoOnInteractor.Companion.ENABLED
+import com.android.systemui.qs.tiles.dialog.bluetooth.BluetoothAutoOnRepository.Companion.SETTING_NAME
+import com.android.systemui.qs.tiles.dialog.bluetooth.BluetoothAutoOnRepository.Companion.UNSET
+import com.android.systemui.user.data.repository.FakeUserRepository
+import com.android.systemui.util.settings.FakeSettings
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class BluetoothAutoOnRepositoryTest : SysuiTestCase() {
+ @get:Rule val mockitoRule: MockitoRule = MockitoJUnit.rule()
+ private val testDispatcher = StandardTestDispatcher()
+ private val testScope = TestScope(testDispatcher)
+ private var secureSettings: FakeSettings = FakeSettings()
+ private val userRepository: FakeUserRepository = FakeUserRepository()
+
+ private lateinit var bluetoothAutoOnRepository: BluetoothAutoOnRepository
+
+ @Before
+ fun setUp() {
+ bluetoothAutoOnRepository =
+ BluetoothAutoOnRepository(
+ secureSettings,
+ userRepository,
+ testScope.backgroundScope,
+ testDispatcher
+ )
+
+ userRepository.setUserInfos(listOf(SECONDARY_USER, SYSTEM_USER))
+ }
+
+ @Test
+ fun testGetValue_valueUnset() {
+ testScope.runTest {
+ userRepository.setSelectedUserInfo(SYSTEM_USER)
+ val actualValue by collectLastValue(bluetoothAutoOnRepository.getValue)
+
+ runCurrent()
+
+ assertThat(actualValue).isEqualTo(UNSET)
+ assertThat(bluetoothAutoOnRepository.isValuePresent()).isFalse()
+ }
+ }
+
+ @Test
+ fun testGetValue_valueFalse() {
+ testScope.runTest {
+ userRepository.setSelectedUserInfo(SYSTEM_USER)
+ val actualValue by collectLastValue(bluetoothAutoOnRepository.getValue)
+
+ secureSettings.putIntForUser(SETTING_NAME, DISABLED, UserHandle.USER_SYSTEM)
+ runCurrent()
+
+ assertThat(actualValue).isEqualTo(DISABLED)
+ }
+ }
+
+ @Test
+ fun testGetValue_valueTrue() {
+ testScope.runTest {
+ userRepository.setSelectedUserInfo(SYSTEM_USER)
+ val actualValue by collectLastValue(bluetoothAutoOnRepository.getValue)
+
+ secureSettings.putIntForUser(SETTING_NAME, ENABLED, UserHandle.USER_SYSTEM)
+ runCurrent()
+
+ assertThat(actualValue).isEqualTo(ENABLED)
+ }
+ }
+
+ @Test
+ fun testGetValue_valueTrue_secondaryUser_returnUnset() {
+ testScope.runTest {
+ userRepository.setSelectedUserInfo(SECONDARY_USER)
+ val actualValue by collectLastValue(bluetoothAutoOnRepository.getValue)
+
+ secureSettings.putIntForUser(SETTING_NAME, ENABLED, SECONDARY_USER_ID)
+ runCurrent()
+
+ assertThat(actualValue).isEqualTo(UNSET)
+ }
+ }
+
+ companion object {
+ private const val SYSTEM_USER_ID = 0
+ private const val SECONDARY_USER_ID = 1
+ private val SYSTEM_USER =
+ UserInfo(/* id= */ SYSTEM_USER_ID, /* name= */ "system user", /* flags= */ 0)
+ private val SECONDARY_USER =
+ UserInfo(/* id= */ SECONDARY_USER_ID, /* name= */ "secondary user", /* flags= */ 0)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogTest.kt
index b6ddb62..70b0417 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogTest.kt
@@ -71,7 +71,11 @@
@Mock private lateinit var logger: BluetoothTileDialogLogger
- private val uiProperties = BluetoothTileDialogViewModel.UiProperties.build(ENABLED)
+ private val uiProperties =
+ BluetoothTileDialogViewModel.UiProperties.build(
+ isBluetoothEnabled = ENABLED,
+ isAutoOnToggleFeatureAvailable = ENABLED
+ )
private val fakeSystemClock = FakeSystemClock()
@@ -305,7 +309,7 @@
bluetoothTileDialog =
BluetoothTileDialog(
ENABLED,
- BluetoothTileDialogViewModel.UiProperties.build(ENABLED),
+ BluetoothTileDialogViewModel.UiProperties.build(ENABLED, ENABLED),
MATCH_PARENT,
bluetoothTileDialogCallback,
dispatcher,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModelTest.kt
index a5576e0..cb9f4b4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModelTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.qs.tiles.dialog.bluetooth
import android.content.SharedPreferences
+import android.content.pm.UserInfo
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.View
@@ -30,9 +31,11 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.DialogTransitionAnimator
import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.user.data.repository.FakeUserRepository
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.nullable
+import com.android.systemui.util.settings.FakeSettings
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.CoroutineDispatcher
@@ -88,6 +91,8 @@
private lateinit var scheduler: TestCoroutineScheduler
private lateinit var dispatcher: CoroutineDispatcher
private lateinit var testScope: TestScope
+ private lateinit var secureSettings: FakeSettings
+ private lateinit var userRepository: FakeUserRepository
@Before
fun setUp() {
@@ -95,10 +100,27 @@
scheduler = TestCoroutineScheduler()
dispatcher = UnconfinedTestDispatcher(scheduler)
testScope = TestScope(dispatcher)
+ secureSettings = FakeSettings()
+ userRepository = FakeUserRepository()
+ userRepository.setUserInfos(listOf(SYSTEM_USER))
+ secureSettings.putIntForUser(
+ BluetoothAutoOnRepository.SETTING_NAME,
+ BluetoothAutoOnInteractor.ENABLED,
+ SYSTEM_USER_ID
+ )
bluetoothTileDialogViewModel =
BluetoothTileDialogViewModel(
deviceItemInteractor,
bluetoothStateInteractor,
+ // TODO(b/316822488): Create FakeBluetoothAutoOnInteractor.
+ BluetoothAutoOnInteractor(
+ BluetoothAutoOnRepository(
+ secureSettings,
+ userRepository,
+ testScope.backgroundScope,
+ dispatcher
+ )
+ ),
mDialogTransitionAnimator,
activityStarter,
fakeSystemClock,
@@ -183,7 +205,11 @@
@Test
fun testBuildUiProperties_bluetoothOn_shouldHideAutoOn() {
testScope.runTest {
- val actual = BluetoothTileDialogViewModel.UiProperties.build(true)
+ val actual =
+ BluetoothTileDialogViewModel.UiProperties.build(
+ isBluetoothEnabled = true,
+ isAutoOnToggleFeatureAvailable = true
+ )
assertThat(actual.autoOnToggleVisibility).isEqualTo(GONE)
}
}
@@ -191,26 +217,48 @@
@Test
fun testBuildUiProperties_bluetoothOff_shouldShowAutoOn() {
testScope.runTest {
- val actual = BluetoothTileDialogViewModel.UiProperties.build(false)
+ val actual =
+ BluetoothTileDialogViewModel.UiProperties.build(
+ isBluetoothEnabled = false,
+ isAutoOnToggleFeatureAvailable = true
+ )
assertThat(actual.autoOnToggleVisibility).isEqualTo(VISIBLE)
}
}
@Test
- fun testBuildUiProperties_flagOff_bluetoothOff_shouldHideAutoOn() {
+ fun testBuildUiProperties_bluetoothOff_autoOnFeatureUnavailable_shouldHideAutoOn() {
testScope.runTest {
- mSetFlagsRule.disableFlags(Flags.FLAG_BLUETOOTH_QS_TILE_DIALOG_AUTO_ON_TOGGLE)
- val actual = BluetoothTileDialogViewModel.UiProperties.build(false)
+ val actual =
+ BluetoothTileDialogViewModel.UiProperties.build(
+ isBluetoothEnabled = false,
+ isAutoOnToggleFeatureAvailable = false
+ )
assertThat(actual.autoOnToggleVisibility).isEqualTo(GONE)
}
}
@Test
- fun testBuildUiProperties_flagOff_bluetoothOn_shouldHideAutoOn() {
+ fun testIsAutoOnToggleFeatureAvailable_flagOn_settingValueSet_returnTrue() {
+ testScope.runTest {
+ val actual = bluetoothTileDialogViewModel.isAutoOnToggleFeatureAvailable()
+ assertThat(actual).isTrue()
+ }
+ }
+
+ @Test
+ fun testIsAutoOnToggleFeatureAvailable_flagOff_settingValueSet_returnFalse() {
testScope.runTest {
mSetFlagsRule.disableFlags(Flags.FLAG_BLUETOOTH_QS_TILE_DIALOG_AUTO_ON_TOGGLE)
- val actual = BluetoothTileDialogViewModel.UiProperties.build(true)
- assertThat(actual.autoOnToggleVisibility).isEqualTo(GONE)
+
+ val actual = bluetoothTileDialogViewModel.isAutoOnToggleFeatureAvailable()
+ assertThat(actual).isFalse()
}
}
+
+ companion object {
+ private const val SYSTEM_USER_ID = 0
+ private val SYSTEM_USER =
+ UserInfo(/* id= */ SYSTEM_USER_ID, /* name= */ "system user", /* flags= */ 0)
+ }
}