Merge changes I2e87eb59,I34141bb3,I289fce00 into main
* changes:
Read and write auto on toggle value.
Add auto on toggle UI.
Move bluetooth_qs_tile_dialog_auto_on_toggle to settingslib.
diff --git a/packages/SettingsLib/aconfig/settingslib.aconfig b/packages/SettingsLib/aconfig/settingslib.aconfig
index bab6781..d622eb8 100644
--- a/packages/SettingsLib/aconfig/settingslib.aconfig
+++ b/packages/SettingsLib/aconfig/settingslib.aconfig
@@ -17,3 +17,9 @@
}
}
+flag {
+ name: "bluetooth_qs_tile_dialog_auto_on_toggle"
+ namespace: "bluetooth"
+ description: "Displays the auto on toggle in the bluetooth QS tile dialog"
+ bug: "316985153"
+}
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index 7a4e60a..56576f1 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -354,13 +354,6 @@
}
flag {
- name: "bluetooth_qs_tile_dialog_auto_on_toggle"
- namespace: "systemui"
- description: "Displays the auto on toggle in the bluetooth QS tile dialog"
- bug: "316985153"
-}
-
-flag {
name: "smartspace_relocate_to_bottom"
namespace: "systemui"
description: "Relocate Smartspace to bottom of the Lock Screen"
diff --git a/packages/SystemUI/res/layout/bluetooth_tile_dialog.xml b/packages/SystemUI/res/layout/bluetooth_tile_dialog.xml
index a0f916c..ac781ec 100644
--- a/packages/SystemUI/res/layout/bluetooth_tile_dialog.xml
+++ b/packages/SystemUI/res/layout/bluetooth_tile_dialog.xml
@@ -81,7 +81,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="21dp"
- android:minHeight="145dp"
+ android:minHeight="@dimen/bluetooth_dialog_scroll_view_min_height"
android:fillViewport="true"
app:layout_constrainedHeight="true"
app:layout_constraintStart_toStartOf="parent"
@@ -97,11 +97,11 @@
<TextView
android:id="@+id/bluetooth_toggle_title"
android:layout_width="0dp"
- android:layout_height="64dp"
- android:maxLines="1"
+ android:layout_height="68dp"
+ android:maxLines="2"
android:ellipsize="end"
android:gravity="start|center_vertical"
- android:paddingEnd="0dp"
+ android:paddingEnd="15dp"
android:paddingStart="36dp"
android:text="@string/turn_on_bluetooth"
android:clickable="false"
@@ -114,7 +114,7 @@
<Switch
android:id="@+id/bluetooth_toggle"
android:layout_width="wrap_content"
- android:layout_height="64dp"
+ android:layout_height="68dp"
android:gravity="start|center_vertical"
android:paddingEnd="40dp"
android:contentDescription="@string/turn_on_bluetooth"
@@ -126,14 +126,79 @@
app:layout_constraintStart_toEndOf="@+id/bluetooth_toggle_title"
app:layout_constraintTop_toTopOf="parent" />
+ <androidx.constraintlayout.widget.Group
+ android:id="@+id/bluetooth_auto_on_toggle_layout"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:visibility="gone"
+ app:constraint_referenced_ids="bluetooth_auto_on_toggle_title,bluetooth_auto_on_toggle,bluetooth_auto_on_toggle_info_icon,bluetooth_auto_on_toggle_info_text" />
+
+ <TextView
+ android:id="@+id/bluetooth_auto_on_toggle_title"
+ android:layout_width="0dp"
+ android:layout_height="68dp"
+ android:layout_marginBottom="20dp"
+ android:maxLines="2"
+ android:ellipsize="end"
+ android:text="@string/turn_on_bluetooth_auto_tomorrow"
+ android:gravity="start|center_vertical"
+ android:paddingEnd="15dp"
+ android:paddingStart="36dp"
+ android:clickable="false"
+ android:textAppearance="@style/TextAppearance.Dialog.Title"
+ android:textSize="16sp"
+ app:layout_constraintEnd_toStartOf="@+id/bluetooth_auto_on_toggle"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/bluetooth_toggle_title" />
+
+ <Switch
+ android:id="@+id/bluetooth_auto_on_toggle"
+ android:layout_width="wrap_content"
+ android:layout_height="68dp"
+ android:layout_marginBottom="20dp"
+ android:gravity="start|center_vertical"
+ android:paddingEnd="40dp"
+ android:contentDescription="@string/turn_on_bluetooth_auto_tomorrow"
+ android:switchMinWidth="@dimen/settingslib_switch_track_width"
+ android:theme="@style/MainSwitch.Settingslib"
+ android:thumb="@drawable/settingslib_thumb_selector"
+ android:track="@drawable/settingslib_track_selector"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toEndOf="@+id/bluetooth_auto_on_toggle_title"
+ app:layout_constraintTop_toBottomOf="@+id/bluetooth_toggle" />
+
+ <ImageView
+ android:id="@+id/bluetooth_auto_on_toggle_info_icon"
+ android:src="@drawable/ic_info_outline"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:tint="?android:attr/textColorTertiary"
+ android:paddingStart="36dp"
+ android:layout_marginTop="20dp"
+ android:layout_marginBottom="@dimen/bluetooth_dialog_layout_margin"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/bluetooth_auto_on_toggle" />
+
+ <TextView
+ android:id="@+id/bluetooth_auto_on_toggle_info_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="20dp"
+ android:paddingStart="36dp"
+ android:paddingEnd="40dp"
+ android:text="@string/turn_on_bluetooth_auto_info"
+ android:textAppearance="@style/TextAppearance.Dialog.Body.Message"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/bluetooth_auto_on_toggle_info_icon" />
+
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/device_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/bluetooth_toggle"
- app:layout_constraintBottom_toTopOf="@+id/see_all_button" />
+ app:layout_constraintTop_toBottomOf="@+id/bluetooth_toggle" />
<Button
android:id="@+id/see_all_button"
@@ -168,12 +233,10 @@
android:background="@drawable/bluetooth_tile_dialog_bg_off"
android:layout_width="0dp"
android:layout_height="64dp"
- android:layout_marginBottom="9dp"
android:contentDescription="@string/accessibility_bluetooth_device_settings_pair_new_device"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/see_all_button"
- app:layout_constraintBottom_toTopOf="@+id/done_button"
android:drawableStart="@drawable/ic_add"
android:drawablePadding="20dp"
android:drawableTint="?android:attr/textColorPrimary"
@@ -186,11 +249,19 @@
android:ellipsize="end"
android:visibility="gone" />
+ <androidx.constraintlayout.widget.Barrier
+ android:id="@+id/barrier"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ app:barrierDirection="bottom"
+ app:constraint_referenced_ids="pair_new_device_button,bluetooth_auto_on_toggle_info_text" />
+
<Button
android:id="@+id/done_button"
style="@style/Widget.Dialog.Button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_marginTop="9dp"
android:layout_marginBottom="@dimen/dialog_bottom_padding"
android:layout_marginEnd="@dimen/dialog_side_padding"
android:layout_marginStart="@dimen/dialog_side_padding"
@@ -200,7 +271,9 @@
android:maxLines="1"
android:text="@string/inline_done_button"
app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintBottom_toBottomOf="parent" />
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/barrier"
+ app:layout_constraintVertical_bias="1" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index cc31754..7537a00 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1717,6 +1717,10 @@
<dimen name="bluetooth_dialog_layout_margin">16dp</dimen>
<!-- The height of the bluetooth device in bluetooth dialog. -->
<dimen name="bluetooth_dialog_device_height">72dp</dimen>
+ <!-- The height of the main scroll view in bluetooth dialog. -->
+ <dimen name="bluetooth_dialog_scroll_view_min_height">145dp</dimen>
+ <!-- The height of the main scroll view in bluetooth dialog with auto on toggle. -->
+ <dimen name="bluetooth_dialog_scroll_view_min_height_with_auto_on">350dp</dimen>
<!-- Height percentage of the parent container occupied by the communal view -->
<item name="communal_source_height_percentage" format="float" type="dimen">0.80</item>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 64c6cfa..e401c71 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -669,6 +669,10 @@
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect">disconnect</string>
<!-- QuickSettings: Accessibility label to activate a device [CHAR LIMIT=NONE]-->
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate">activate</string>
+ <!-- QuickSettings: Bluetooth auto on tomorrow [CHAR LIMIT=NONE]-->
+ <string name="turn_on_bluetooth_auto_tomorrow">Automatically turn on again tomorrow</string>
+ <!-- QuickSettings: Bluetooth auto on info text [CHAR LIMIT=NONE]-->
+ <string name="turn_on_bluetooth_auto_info">Features like Quick Share, Find My Device, and device location use Bluetooth</string>
<!-- QuickSettings: Bluetooth secondary label for the battery level of a connected device [CHAR LIMIT=20]-->
<string name="quick_settings_bluetooth_secondary_label_battery_level"><xliff:g id="battery_level_as_percentage">%s</xliff:g> battery</string>
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 1a06c38..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
@@ -56,7 +56,7 @@
internal class BluetoothTileDialog
constructor(
private val bluetoothToggleInitialValue: Boolean,
- private val subtitleResIdInitialValue: Int,
+ private val initialUiProperties: BluetoothTileDialogViewModel.UiProperties,
private val cachedContentHeight: Int,
private val bluetoothTileDialogCallback: BluetoothTileDialogCallback,
@Main private val mainDispatcher: CoroutineDispatcher,
@@ -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,8 @@
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
private lateinit var pairNewDeviceButton: View
@@ -108,6 +114,8 @@
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)
pairNewDeviceButton = requireViewById(R.id.pair_new_device_button)
@@ -116,7 +124,7 @@
setupToggle()
setupRecyclerView()
- subtitleTextView.text = context.getString(subtitleResIdInitialValue)
+ subtitleTextView.text = context.getString(initialUiProperties.subTitleResId)
doneButton.setOnClickListener { dismiss() }
seeAllButton.setOnClickListener { bluetoothTileDialogCallback.onSeeAllClicked(it) }
pairNewDeviceButton.setOnClickListener {
@@ -124,7 +132,9 @@
}
requireViewById<View>(R.id.scroll_view).apply {
scrollViewContent = this
- layoutParams.height = cachedContentHeight
+ minimumHeight =
+ resources.getDimensionPixelSize(initialUiProperties.scrollViewMinHeightResId)
+ layoutParams.height = maxOf(cachedContentHeight, minimumHeight)
}
progressBarAnimation = requireViewById(R.id.bluetooth_tile_dialog_progress_animation)
progressBarBackground = requireViewById(R.id.bluetooth_tile_dialog_progress_background)
@@ -178,13 +188,27 @@
}
}
- internal fun onBluetoothStateUpdated(isEnabled: Boolean, subtitleResId: Int) {
+ internal fun onBluetoothStateUpdated(
+ isEnabled: Boolean,
+ uiProperties: BluetoothTileDialogViewModel.UiProperties
+ ) {
toggleView.apply {
isChecked = isEnabled
setEnabled(true)
alpha = ENABLED_ALPHA
}
- subtitleTextView.text = context.getString(subtitleResId)
+ subtitleTextView.text = context.getString(uiProperties.subTitleResId)
+ autoOnToggleView.visibility = uiProperties.autoOnToggleVisibility
+ }
+
+ internal fun onBluetoothAutoOnUpdated(isEnabled: Boolean) {
+ if (::autoOnToggle.isInitialized) {
+ autoOnToggle.apply {
+ isChecked = isEnabled
+ setEnabled(true)
+ alpha = ENABLED_ALPHA
+ }
+ }
}
private fun setupToggle() {
@@ -198,6 +222,16 @@
logger.logBluetoothState(BluetoothStateStage.USER_TOGGLED, isChecked.toString())
uiEventLogger.log(BluetoothTileDialogUiEvent.BLUETOOTH_TOGGLE_CLICKED)
}
+
+ 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 54bb95c..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
@@ -21,9 +21,15 @@
import android.content.SharedPreferences
import android.os.Bundle
import android.view.View
+import android.view.View.GONE
+import android.view.View.VISIBLE
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
import com.android.systemui.Prefs
import com.android.systemui.animation.DialogCuj
import com.android.systemui.animation.DialogTransitionAnimator
@@ -58,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,
@@ -143,7 +150,10 @@
bluetoothStateInteractor.bluetoothStateUpdate
.filterNotNull()
.onEach {
- dialog.onBluetoothStateUpdated(it, getSubtitleResId(it))
+ dialog.onBluetoothStateUpdated(
+ it,
+ UiProperties.build(it, isAutoOnToggleFeatureAvailable())
+ )
updateDeviceItemJob?.cancel()
updateDeviceItemJob = launch {
deviceItemInteractor.updateDeviceItems(
@@ -177,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() } }
}
}
@@ -192,7 +217,10 @@
return BluetoothTileDialog(
bluetoothStateInteractor.isBluetoothEnabled,
- getSubtitleResId(bluetoothStateInteractor.isBluetoothEnabled),
+ UiProperties.build(
+ bluetoothStateInteractor.isBluetoothEnabled,
+ isAutoOnToggleFeatureAvailable()
+ ),
cachedContentHeight,
this@BluetoothTileDialogViewModel,
mainDispatcher,
@@ -244,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
@@ -251,6 +283,29 @@
if (isBluetoothEnabled) R.string.quick_settings_bluetooth_tile_subtitle
else R.string.bt_is_off
}
+
+ internal data class UiProperties(
+ @StringRes val subTitleResId: Int,
+ val autoOnToggleVisibility: Int,
+ @DimenRes val scrollViewMinHeightResId: Int,
+ ) {
+ companion object {
+ internal fun build(
+ isBluetoothEnabled: Boolean,
+ isAutoOnToggleFeatureAvailable: Boolean
+ ) =
+ UiProperties(
+ subTitleResId = getSubtitleResId(isBluetoothEnabled),
+ autoOnToggleVisibility =
+ if (isAutoOnToggleFeatureAvailable && !isBluetoothEnabled) VISIBLE
+ else GONE,
+ scrollViewMinHeightResId =
+ if (isAutoOnToggleFeatureAvailable)
+ R.dimen.bluetooth_dialog_scroll_view_min_height_with_auto_on
+ else R.dimen.bluetooth_dialog_scroll_view_min_height
+ )
+ }
+ }
}
internal interface BluetoothTileDialogCallback {
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 154aa1c..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 subtitleResId = R.string.quick_settings_bluetooth_tile_subtitle
+ private val uiProperties =
+ BluetoothTileDialogViewModel.UiProperties.build(
+ isBluetoothEnabled = ENABLED,
+ isAutoOnToggleFeatureAvailable = ENABLED
+ )
private val fakeSystemClock = FakeSystemClock()
@@ -90,7 +94,7 @@
bluetoothTileDialog =
BluetoothTileDialog(
ENABLED,
- subtitleResId,
+ uiProperties,
CONTENT_HEIGHT,
bluetoothTileDialogCallback,
dispatcher,
@@ -131,7 +135,7 @@
bluetoothTileDialog =
BluetoothTileDialog(
ENABLED,
- subtitleResId,
+ uiProperties,
CONTENT_HEIGHT,
bluetoothTileDialogCallback,
dispatcher,
@@ -166,7 +170,7 @@
val viewHolder =
BluetoothTileDialog(
ENABLED,
- subtitleResId,
+ uiProperties,
CONTENT_HEIGHT,
bluetoothTileDialogCallback,
dispatcher,
@@ -194,7 +198,7 @@
val viewHolder =
BluetoothTileDialog(
ENABLED,
- subtitleResId,
+ uiProperties,
CONTENT_HEIGHT,
bluetoothTileDialogCallback,
dispatcher,
@@ -219,7 +223,7 @@
bluetoothTileDialog =
BluetoothTileDialog(
ENABLED,
- subtitleResId,
+ uiProperties,
CONTENT_HEIGHT,
bluetoothTileDialogCallback,
dispatcher,
@@ -253,12 +257,36 @@
}
@Test
- fun testShowDialog_displayFromCachedHeight() {
+ fun testShowDialog_cachedHeightLargerThanMinHeight_displayFromCachedHeight() {
+ testScope.runTest {
+ val cachedHeight = Int.MAX_VALUE
+ bluetoothTileDialog =
+ BluetoothTileDialog(
+ ENABLED,
+ uiProperties,
+ cachedHeight,
+ bluetoothTileDialogCallback,
+ dispatcher,
+ fakeSystemClock,
+ uiEventLogger,
+ logger,
+ mContext
+ )
+ bluetoothTileDialog.show()
+ assertThat(
+ bluetoothTileDialog.requireViewById<View>(R.id.scroll_view).layoutParams.height
+ )
+ .isEqualTo(cachedHeight)
+ }
+ }
+
+ @Test
+ fun testShowDialog_cachedHeightLessThanMinHeight_displayFromUiProperties() {
testScope.runTest {
bluetoothTileDialog =
BluetoothTileDialog(
ENABLED,
- subtitleResId,
+ uiProperties,
MATCH_PARENT,
bluetoothTileDialogCallback,
dispatcher,
@@ -271,7 +299,32 @@
assertThat(
bluetoothTileDialog.requireViewById<View>(R.id.scroll_view).layoutParams.height
)
- .isEqualTo(MATCH_PARENT)
+ .isGreaterThan(MATCH_PARENT)
+ }
+ }
+
+ @Test
+ fun testShowDialog_bluetoothEnabled_autoOnToggleGone() {
+ testScope.runTest {
+ bluetoothTileDialog =
+ BluetoothTileDialog(
+ ENABLED,
+ BluetoothTileDialogViewModel.UiProperties.build(ENABLED, ENABLED),
+ MATCH_PARENT,
+ bluetoothTileDialogCallback,
+ dispatcher,
+ fakeSystemClock,
+ uiEventLogger,
+ logger,
+ mContext
+ )
+ bluetoothTileDialog.show()
+ assertThat(
+ bluetoothTileDialog
+ .requireViewById<View>(R.id.bluetooth_auto_on_toggle_layout)
+ .visibility
+ )
+ .isEqualTo(GONE)
}
}
}
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 98ac17b..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,20 +17,27 @@
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
+import android.view.View.GONE
+import android.view.View.VISIBLE
import android.widget.LinearLayout
import androidx.test.filters.SmallTest
import com.android.internal.logging.UiEventLogger
import com.android.settingslib.bluetooth.CachedBluetoothDevice
+import com.android.settingslib.flags.Flags
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
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
@@ -84,16 +91,36 @@
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() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_BLUETOOTH_QS_TILE_DIALOG_AUTO_ON_TOGGLE)
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,
@@ -174,4 +201,64 @@
verify(activityStarter).postStartActivityDismissingKeyguard(any(), anyInt(), nullable())
}
}
+
+ @Test
+ fun testBuildUiProperties_bluetoothOn_shouldHideAutoOn() {
+ testScope.runTest {
+ val actual =
+ BluetoothTileDialogViewModel.UiProperties.build(
+ isBluetoothEnabled = true,
+ isAutoOnToggleFeatureAvailable = true
+ )
+ assertThat(actual.autoOnToggleVisibility).isEqualTo(GONE)
+ }
+ }
+
+ @Test
+ fun testBuildUiProperties_bluetoothOff_shouldShowAutoOn() {
+ testScope.runTest {
+ val actual =
+ BluetoothTileDialogViewModel.UiProperties.build(
+ isBluetoothEnabled = false,
+ isAutoOnToggleFeatureAvailable = true
+ )
+ assertThat(actual.autoOnToggleVisibility).isEqualTo(VISIBLE)
+ }
+ }
+
+ @Test
+ fun testBuildUiProperties_bluetoothOff_autoOnFeatureUnavailable_shouldHideAutoOn() {
+ testScope.runTest {
+ val actual =
+ BluetoothTileDialogViewModel.UiProperties.build(
+ isBluetoothEnabled = false,
+ isAutoOnToggleFeatureAvailable = false
+ )
+ assertThat(actual.autoOnToggleVisibility).isEqualTo(GONE)
+ }
+ }
+
+ @Test
+ 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.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)
+ }
}