Refactor BluetoothTileDialog into BluetoothTileDialogDelegate
Removes the SystemUIDialog from BluetoothTileDialog
Flag: NA
Test: atest SystemUITests:com.android.systemui.qs.tiles.dialog.bluetooth
Bug: 219008720
Change-Id: Ieea93e483fd3a33ae193791f7e92d472e53ce5ea
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/BluetoothTileDialogDelegate.kt
similarity index 67%
rename from packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialog.kt
rename to packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogDelegate.kt
index 6b53c7a..7ece6e0 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/BluetoothTileDialogDelegate.kt
@@ -37,11 +37,13 @@
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.android.internal.logging.UiEventLogger
-import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.res.R
import com.android.systemui.statusbar.phone.SystemUIDialog
import com.android.systemui.util.time.SystemClock
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableSharedFlow
@@ -52,19 +54,24 @@
import kotlinx.coroutines.withContext
/** Dialog for showing active, connected and saved bluetooth devices. */
-@SysUISingleton
-internal class BluetoothTileDialog
-constructor(
- private val bluetoothToggleInitialValue: Boolean,
- private val initialUiProperties: BluetoothTileDialogViewModel.UiProperties,
- private val cachedContentHeight: Int,
- private val bluetoothTileDialogCallback: BluetoothTileDialogCallback,
+class BluetoothTileDialogDelegate
+@AssistedInject
+internal constructor(
+ @Assisted private val context: Context,
+ @Assisted private val initialUiProperties: BluetoothTileDialogViewModel.UiProperties,
+ @Assisted private val cachedContentHeight: Int,
+ @Assisted private val bluetoothToggleInitialValue: Boolean,
+ @Assisted private val bluetoothTileDialogCallback: BluetoothTileDialogCallback,
+ @Assisted private val dismissListener: Runnable,
@Main private val mainDispatcher: CoroutineDispatcher,
private val systemClock: SystemClock,
private val uiEventLogger: UiEventLogger,
private val logger: BluetoothTileDialogLogger,
- context: Context,
-) : SystemUIDialog(context, DEFAULT_THEME, DEFAULT_DISMISS_ON_DEVICE_LOCK) {
+ private val systemuiDialogFactory: SystemUIDialog.Factory,
+ mainLayoutInflater: LayoutInflater,
+) : SystemUIDialog.Delegate {
+
+ private val layoutInflater = mainLayoutInflater.cloneInContext(context)
private val mutableBluetoothStateToggle: MutableStateFlow<Boolean> =
MutableStateFlow(bluetoothToggleInitialValue)
@@ -91,78 +98,72 @@
private var lastItemRow: Int = -1
- 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
- private lateinit var deviceListView: RecyclerView
- private lateinit var scrollViewContent: View
- private lateinit var progressBarAnimation: ProgressBar
- private lateinit var progressBarBackground: View
+ @AssistedFactory
+ internal interface Factory {
+ fun create(
+ context: Context,
+ initialUiProperties: BluetoothTileDialogViewModel.UiProperties,
+ cachedContentHeight: Int,
+ bluetoothEnabled: Boolean,
+ dialogCallback: BluetoothTileDialogCallback,
+ dimissListener: Runnable
+ ): BluetoothTileDialogDelegate
+ }
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
+ override fun createDialog(): SystemUIDialog {
+ val dialog = systemuiDialogFactory.create(this, context)
+
+ return dialog
+ }
+
+ override fun onCreate(dialog: SystemUIDialog, savedInstanceState: Bundle?) {
+ SystemUIDialog.registerDismissListener(dialog, dismissListener)
uiEventLogger.log(BluetoothTileDialogUiEvent.BLUETOOTH_TILE_DIALOG_SHOWN)
- LayoutInflater.from(context).inflate(R.layout.bluetooth_tile_dialog, null).apply {
+ layoutInflater.inflate(R.layout.bluetooth_tile_dialog, null).apply {
accessibilityPaneTitle = context.getText(R.string.accessibility_desc_quick_settings)
- setContentView(this)
+ dialog.setContentView(this)
}
- 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)
- deviceListView = requireViewById<RecyclerView>(R.id.device_list)
+ setupToggle(dialog)
+ setupRecyclerView(dialog)
- setupToggle()
- setupRecyclerView()
-
- subtitleTextView.text = context.getString(initialUiProperties.subTitleResId)
- doneButton.setOnClickListener { dismiss() }
- seeAllButton.setOnClickListener { bluetoothTileDialogCallback.onSeeAllClicked(it) }
- pairNewDeviceButton.setOnClickListener {
+ getSubtitleTextView(dialog).text = context.getString(initialUiProperties.subTitleResId)
+ dialog.requireViewById<View>(R.id.done_button).setOnClickListener { dialog.dismiss() }
+ getSeeAllButton(dialog).setOnClickListener {
+ bluetoothTileDialogCallback.onSeeAllClicked(it)
+ }
+ getPairNewDeviceButton(dialog).setOnClickListener {
bluetoothTileDialogCallback.onPairNewDeviceClicked(it)
}
- requireViewById<View>(R.id.scroll_view).apply {
- scrollViewContent = this
+ getScrollViewContent(dialog).apply {
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)
}
- override fun start() {
+ override fun onStart(dialog: SystemUIDialog) {
lastUiUpdateMs = systemClock.elapsedRealtime()
}
- override fun dismiss() {
- if (::scrollViewContent.isInitialized) {
- mutableContentHeight.tryEmit(scrollViewContent.measuredHeight)
- }
- super.dismiss()
+ override fun onStop(dialog: SystemUIDialog) {
+ mutableContentHeight.tryEmit(getScrollViewContent(dialog).measuredHeight)
}
- internal suspend fun animateProgressBar(animate: Boolean) {
+ internal suspend fun animateProgressBar(dialog: SystemUIDialog, animate: Boolean) {
withContext(mainDispatcher) {
if (animate) {
- showProgressBar()
+ showProgressBar(dialog)
} else {
delay(PROGRESS_BAR_ANIMATION_DURATION_MS)
- hideProgressBar()
+ hideProgressBar(dialog)
}
}
}
internal suspend fun onDeviceItemUpdated(
+ dialog: SystemUIDialog,
deviceItem: List<DeviceItem>,
showSeeAll: Boolean,
showPairNewDevice: Boolean
@@ -176,10 +177,11 @@
}
if (isActive) {
deviceItemAdapter.refreshDeviceItemList(deviceItem) {
- seeAllButton.visibility = if (showSeeAll) VISIBLE else GONE
- pairNewDeviceButton.visibility = if (showPairNewDevice) VISIBLE else GONE
+ getSeeAllButton(dialog).visibility = if (showSeeAll) VISIBLE else GONE
+ getPairNewDeviceButton(dialog).visibility =
+ if (showPairNewDevice) VISIBLE else GONE
// Update the height after data is updated
- scrollViewContent.layoutParams.height = WRAP_CONTENT
+ getScrollViewContent(dialog).layoutParams.height = WRAP_CONTENT
lastUiUpdateMs = systemClock.elapsedRealtime()
lastItemRow = itemRow
logger.logDeviceUiUpdate(lastUiUpdateMs - start)
@@ -189,29 +191,29 @@
}
internal fun onBluetoothStateUpdated(
+ dialog: SystemUIDialog,
isEnabled: Boolean,
uiProperties: BluetoothTileDialogViewModel.UiProperties
) {
- toggleView.apply {
+ getToggleView(dialog).apply {
isChecked = isEnabled
setEnabled(true)
alpha = ENABLED_ALPHA
}
- subtitleTextView.text = context.getString(uiProperties.subTitleResId)
- autoOnToggleView.visibility = uiProperties.autoOnToggleVisibility
+ getSubtitleTextView(dialog).text = context.getString(uiProperties.subTitleResId)
+ getAutoOnToggleView(dialog).visibility = uiProperties.autoOnToggleVisibility
}
- internal fun onBluetoothAutoOnUpdated(isEnabled: Boolean) {
- if (::autoOnToggle.isInitialized) {
- autoOnToggle.apply {
- isChecked = isEnabled
- setEnabled(true)
- alpha = ENABLED_ALPHA
- }
+ internal fun onBluetoothAutoOnUpdated(dialog: SystemUIDialog, isEnabled: Boolean) {
+ getAutoOnToggle(dialog).apply {
+ isChecked = isEnabled
+ setEnabled(true)
+ alpha = ENABLED_ALPHA
}
}
- private fun setupToggle() {
+ private fun setupToggle(dialog: SystemUIDialog) {
+ val toggleView = getToggleView(dialog)
toggleView.isChecked = bluetoothToggleInitialValue
toggleView.setOnCheckedChangeListener { view, isChecked ->
mutableBluetoothStateToggle.value = isChecked
@@ -223,8 +225,8 @@
uiEventLogger.log(BluetoothTileDialogUiEvent.BLUETOOTH_TOGGLE_CLICKED)
}
- autoOnToggleView.visibility = initialUiProperties.autoOnToggleVisibility
- autoOnToggle.setOnCheckedChangeListener { view, isChecked ->
+ getAutoOnToggleView(dialog).visibility = initialUiProperties.autoOnToggleVisibility
+ getAutoOnToggle(dialog).setOnCheckedChangeListener { view, isChecked ->
mutableBluetoothAutoOnToggle.value = isChecked
view.apply {
isEnabled = false
@@ -234,30 +236,66 @@
}
}
- private fun setupRecyclerView() {
- deviceListView.apply {
+ private fun getToggleView(dialog: SystemUIDialog): Switch {
+ return dialog.requireViewById(R.id.bluetooth_toggle)
+ }
+
+ private fun getSubtitleTextView(dialog: SystemUIDialog): TextView {
+ return dialog.requireViewById(R.id.bluetooth_tile_dialog_subtitle)
+ }
+
+ private fun getSeeAllButton(dialog: SystemUIDialog): View {
+ return dialog.requireViewById(R.id.see_all_button)
+ }
+
+ private fun getPairNewDeviceButton(dialog: SystemUIDialog): View {
+ return dialog.requireViewById(R.id.pair_new_device_button)
+ }
+
+ private fun getDeviceListView(dialog: SystemUIDialog): RecyclerView {
+ return dialog.requireViewById(R.id.device_list)
+ }
+
+ private fun getAutoOnToggle(dialog: SystemUIDialog): Switch {
+ return dialog.requireViewById(R.id.bluetooth_auto_on_toggle)
+ }
+
+ private fun getAutoOnToggleView(dialog: SystemUIDialog): View {
+ return dialog.requireViewById(R.id.bluetooth_auto_on_toggle_layout)
+ }
+
+ private fun getProgressBarAnimation(dialog: SystemUIDialog): ProgressBar {
+ return dialog.requireViewById(R.id.bluetooth_tile_dialog_progress_animation)
+ }
+
+ private fun getProgressBarBackground(dialog: SystemUIDialog): View {
+ return dialog.requireViewById(R.id.bluetooth_tile_dialog_progress_animation)
+ }
+
+ private fun getScrollViewContent(dialog: SystemUIDialog): View {
+ return dialog.requireViewById(R.id.scroll_view)
+ }
+
+ private fun setupRecyclerView(dialog: SystemUIDialog) {
+ getDeviceListView(dialog).apply {
layoutManager = LinearLayoutManager(context)
adapter = deviceItemAdapter
}
}
- private fun showProgressBar() {
- if (
- ::progressBarAnimation.isInitialized &&
- ::progressBarBackground.isInitialized &&
- progressBarAnimation.visibility != VISIBLE
- ) {
+ private fun showProgressBar(dialog: SystemUIDialog) {
+ val progressBarAnimation = getProgressBarAnimation(dialog)
+ val progressBarBackground = getProgressBarBackground(dialog)
+ if (progressBarAnimation.visibility != VISIBLE) {
progressBarAnimation.visibility = VISIBLE
progressBarBackground.visibility = INVISIBLE
}
}
- private fun hideProgressBar() {
- if (
- ::progressBarAnimation.isInitialized &&
- ::progressBarBackground.isInitialized &&
- progressBarAnimation.visibility != INVISIBLE
- ) {
+ private fun hideProgressBar(dialog: SystemUIDialog) {
+ val progressBarAnimation = getProgressBarAnimation(dialog)
+ val progressBarBackground = getProgressBarBackground(dialog)
+ if (progressBarAnimation.visibility != INVISIBLE) {
progressBarAnimation.visibility = INVISIBLE
progressBarBackground.visibility = VISIBLE
}
@@ -295,9 +333,7 @@
private val asyncListDiffer = AsyncListDiffer(this, diffUtilCallback)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DeviceItemViewHolder {
- val view =
- LayoutInflater.from(parent.context)
- .inflate(R.layout.bluetooth_device_item, parent, false)
+ val view = layoutInflater.inflate(R.layout.bluetooth_device_item, parent, false)
return DeviceItemViewHolder(view)
}
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 5a14e5f..0486207 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
@@ -38,13 +38,11 @@
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.plugins.ActivityStarter
-import com.android.systemui.qs.tiles.dialog.bluetooth.BluetoothTileDialog.Companion.ACTION_BLUETOOTH_DEVICE_DETAILS
-import com.android.systemui.qs.tiles.dialog.bluetooth.BluetoothTileDialog.Companion.ACTION_PAIR_NEW_DEVICE
-import com.android.systemui.qs.tiles.dialog.bluetooth.BluetoothTileDialog.Companion.ACTION_PREVIOUSLY_CONNECTED_DEVICE
-import com.android.systemui.qs.tiles.dialog.bluetooth.BluetoothTileDialog.Companion.MAX_DEVICE_ITEM_ENTRY
+import com.android.systemui.qs.tiles.dialog.bluetooth.BluetoothTileDialogDelegate.Companion.ACTION_BLUETOOTH_DEVICE_DETAILS
+import com.android.systemui.qs.tiles.dialog.bluetooth.BluetoothTileDialogDelegate.Companion.ACTION_PAIR_NEW_DEVICE
+import com.android.systemui.qs.tiles.dialog.bluetooth.BluetoothTileDialogDelegate.Companion.ACTION_PREVIOUSLY_CONNECTED_DEVICE
+import com.android.systemui.qs.tiles.dialog.bluetooth.BluetoothTileDialogDelegate.Companion.MAX_DEVICE_ITEM_ENTRY
import com.android.systemui.res.R
-import com.android.systemui.statusbar.phone.SystemUIDialog
-import com.android.systemui.util.time.SystemClock
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
@@ -67,13 +65,12 @@
private val bluetoothAutoOnInteractor: BluetoothAutoOnInteractor,
private val dialogTransitionAnimator: DialogTransitionAnimator,
private val activityStarter: ActivityStarter,
- private val systemClock: SystemClock,
private val uiEventLogger: UiEventLogger,
- private val logger: BluetoothTileDialogLogger,
@Application private val coroutineScope: CoroutineScope,
@Main private val mainDispatcher: CoroutineDispatcher,
@Background private val backgroundDispatcher: CoroutineDispatcher,
@Main private val sharedPreferences: SharedPreferences,
+ private val bluetoothDialogDelegateFactory: BluetoothTileDialogDelegate.Factory,
) : BluetoothTileDialogCallback {
private var job: Job? = null
@@ -92,7 +89,8 @@
coroutineScope.launch(mainDispatcher) {
var updateDeviceItemJob: Job?
var updateDialogUiJob: Job? = null
- val dialog = createBluetoothTileDialog(context)
+ val dialogDelegate = createBluetoothTileDialog(context)
+ val dialog = dialogDelegate.createDialog()
view?.let {
dialogTransitionAnimator.showFromView(
@@ -118,13 +116,14 @@
.onEach {
updateDialogUiJob?.cancel()
updateDialogUiJob = launch {
- dialog.apply {
+ dialogDelegate.apply {
onDeviceItemUpdated(
+ dialog,
it.take(MAX_DEVICE_ITEM_ENTRY),
showSeeAll = it.size > MAX_DEVICE_ITEM_ENTRY,
showPairNewDevice = bluetoothStateInteractor.isBluetoothEnabled
)
- animateProgressBar(false)
+ animateProgressBar(dialog, false)
}
}
}
@@ -134,7 +133,7 @@
// the device item list and animiate the progress bar.
deviceItemInteractor.deviceItemUpdateRequest
.onEach {
- dialog.animateProgressBar(true)
+ dialogDelegate.animateProgressBar(dialog, true)
updateDeviceItemJob?.cancel()
updateDeviceItemJob = launch {
deviceItemInteractor.updateDeviceItems(
@@ -150,7 +149,8 @@
bluetoothStateInteractor.bluetoothStateUpdate
.filterNotNull()
.onEach {
- dialog.onBluetoothStateUpdated(
+ dialogDelegate.onBluetoothStateUpdated(
+ dialog,
it,
UiProperties.build(it, isAutoOnToggleFeatureAvailable())
)
@@ -166,20 +166,20 @@
// bluetoothStateToggle is emitted when user toggles the bluetooth state switch,
// send the new value to the bluetoothStateInteractor and animate the progress bar.
- dialog.bluetoothStateToggle
+ dialogDelegate.bluetoothStateToggle
.onEach {
- dialog.animateProgressBar(true)
+ dialogDelegate.animateProgressBar(dialog, true)
bluetoothStateInteractor.isBluetoothEnabled = it
}
.launchIn(this)
// deviceItemClick is emitted when user clicked on a device item.
- dialog.deviceItemClick
+ dialogDelegate.deviceItemClick
.onEach { deviceItemInteractor.updateDeviceItemOnClick(it) }
.launchIn(this)
// contentHeight is emitted when the dialog is dismissed.
- dialog.contentHeight
+ dialogDelegate.contentHeight
.onEach {
withContext(backgroundDispatcher) {
sharedPreferences.edit().putInt(CONTENT_HEIGHT_PREF_KEY, it).apply()
@@ -191,12 +191,12 @@
// bluetoothAutoOnUpdate is emitted when bluetooth auto on on/off state is
// changed.
bluetoothAutoOnInteractor.isEnabled
- .onEach { dialog.onBluetoothAutoOnUpdated(it) }
+ .onEach { dialogDelegate.onBluetoothAutoOnUpdated(dialog, it) }
.launchIn(this)
// bluetoothAutoOnToggle is emitted when user toggles the bluetooth auto on
// switch, send the new value to the bluetoothAutoOnInteractor.
- dialog.bluetoothAutoOnToggle
+ dialogDelegate.bluetoothAutoOnToggle
.filterNotNull()
.onEach { bluetoothAutoOnInteractor.setEnabled(it) }
.launchIn(this)
@@ -206,7 +206,7 @@
}
}
- private suspend fun createBluetoothTileDialog(context: Context): BluetoothTileDialog {
+ private suspend fun createBluetoothTileDialog(context: Context): BluetoothTileDialogDelegate {
val cachedContentHeight =
withContext(backgroundDispatcher) {
sharedPreferences.getInt(
@@ -215,21 +215,17 @@
)
}
- return BluetoothTileDialog(
+ return bluetoothDialogDelegateFactory.create(
+ context,
+ UiProperties.build(
bluetoothStateInteractor.isBluetoothEnabled,
- UiProperties.build(
- bluetoothStateInteractor.isBluetoothEnabled,
- isAutoOnToggleFeatureAvailable()
- ),
- cachedContentHeight,
- this@BluetoothTileDialogViewModel,
- mainDispatcher,
- systemClock,
- uiEventLogger,
- logger,
- context
- )
- .apply { SystemUIDialog.registerDismissListener(this) { cancelJob() } }
+ isAutoOnToggleFeatureAvailable()
+ ),
+ cachedContentHeight,
+ bluetoothStateInteractor.isBluetoothEnabled,
+ this@BluetoothTileDialogViewModel,
+ { cancelJob() }
+ )
}
override fun onDeviceItemGearClicked(deviceItem: DeviceItem, view: View) {
@@ -308,7 +304,7 @@
}
}
-internal interface BluetoothTileDialogCallback {
+interface BluetoothTileDialogCallback {
fun onDeviceItemGearClicked(deviceItem: DeviceItem, view: View)
fun onSeeAllClicked(view: View)
fun onPairNewDeviceClicked(view: View)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogDelegateTest.kt
new file mode 100644
index 0000000..8ecb953
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogDelegateTest.kt
@@ -0,0 +1,347 @@
+/*
+ * 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.content.Context
+import android.graphics.drawable.Drawable
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.view.LayoutInflater
+import android.view.View
+import android.view.View.GONE
+import android.view.View.VISIBLE
+import android.view.ViewGroup.LayoutParams.MATCH_PARENT
+import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import androidx.test.filters.SmallTest
+import com.android.internal.logging.UiEventLogger
+import com.android.settingslib.bluetooth.CachedBluetoothDevice
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.animation.DialogTransitionAnimator
+import com.android.systemui.model.SysUiState
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import com.android.systemui.statusbar.phone.SystemUIDialogManager
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.whenever
+import com.android.systemui.util.time.FakeSystemClock
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.test.TestCoroutineScheduler
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+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.ArgumentMatchers.anyBoolean
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.Mock
+import org.mockito.Mockito.`when`
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+class BluetoothTileDialogDelegateTest : SysuiTestCase() {
+ companion object {
+ const val DEVICE_NAME = "device"
+ const val DEVICE_CONNECTION_SUMMARY = "active"
+ const val ENABLED = true
+ const val CONTENT_HEIGHT = WRAP_CONTENT
+ }
+
+ @get:Rule val mockitoRule: MockitoRule = MockitoJUnit.rule()
+
+ @Mock private lateinit var cachedBluetoothDevice: CachedBluetoothDevice
+
+ @Mock private lateinit var bluetoothTileDialogCallback: BluetoothTileDialogCallback
+
+ @Mock private lateinit var drawable: Drawable
+
+ @Mock private lateinit var uiEventLogger: UiEventLogger
+
+ @Mock private lateinit var logger: BluetoothTileDialogLogger
+
+ private val uiProperties =
+ BluetoothTileDialogViewModel.UiProperties.build(
+ isBluetoothEnabled = ENABLED,
+ isAutoOnToggleFeatureAvailable = ENABLED
+ )
+ @Mock private lateinit var sysuiDialogFactory: SystemUIDialog.Factory
+ @Mock private lateinit var dialogManager: SystemUIDialogManager
+ @Mock private lateinit var sysuiState: SysUiState
+ @Mock private lateinit var dialogTransitionAnimator: DialogTransitionAnimator
+
+ private val fakeSystemClock = FakeSystemClock()
+
+ private lateinit var scheduler: TestCoroutineScheduler
+ private lateinit var dispatcher: CoroutineDispatcher
+ private lateinit var testScope: TestScope
+ private lateinit var icon: Pair<Drawable, String>
+ private lateinit var mBluetoothTileDialogDelegate: BluetoothTileDialogDelegate
+ private lateinit var deviceItem: DeviceItem
+
+ @Before
+ fun setUp() {
+ scheduler = TestCoroutineScheduler()
+ dispatcher = UnconfinedTestDispatcher(scheduler)
+ testScope = TestScope(dispatcher)
+
+ whenever(sysuiState.setFlag(anyInt(), anyBoolean())).thenReturn(sysuiState)
+
+ mBluetoothTileDialogDelegate =
+ BluetoothTileDialogDelegate(
+ mContext,
+ uiProperties,
+ CONTENT_HEIGHT,
+ ENABLED,
+ bluetoothTileDialogCallback,
+ {},
+ dispatcher,
+ fakeSystemClock,
+ uiEventLogger,
+ logger,
+ sysuiDialogFactory,
+ LayoutInflater.from(mContext)
+ )
+
+ whenever(
+ sysuiDialogFactory.create(
+ any(SystemUIDialog.Delegate::class.java),
+ any(Context::class.java)
+ )
+ )
+ .thenAnswer {
+ SystemUIDialog(
+ mContext,
+ 0,
+ SystemUIDialog.DEFAULT_DISMISS_ON_DEVICE_LOCK,
+ dialogManager,
+ sysuiState,
+ fakeBroadcastDispatcher,
+ dialogTransitionAnimator,
+ it.getArgument(0)
+ )
+ }
+
+ icon = Pair(drawable, DEVICE_NAME)
+ deviceItem =
+ DeviceItem(
+ type = DeviceItemType.AVAILABLE_MEDIA_BLUETOOTH_DEVICE,
+ cachedBluetoothDevice = cachedBluetoothDevice,
+ deviceName = DEVICE_NAME,
+ connectionSummary = DEVICE_CONNECTION_SUMMARY,
+ iconWithDescription = icon,
+ background = null
+ )
+ `when`(cachedBluetoothDevice.isBusy).thenReturn(false)
+ }
+
+ @Test
+ fun testShowDialog_createRecyclerViewWithAdapter() {
+ val dialog = mBluetoothTileDialogDelegate.createDialog()
+ dialog.show()
+
+ val recyclerView = dialog.requireViewById<RecyclerView>(R.id.device_list)
+
+ assertThat(recyclerView).isNotNull()
+ assertThat(recyclerView.visibility).isEqualTo(VISIBLE)
+ assertThat(recyclerView.adapter).isNotNull()
+ assertThat(recyclerView.layoutManager is LinearLayoutManager).isTrue()
+ }
+
+ @Test
+ fun testShowDialog_displayBluetoothDevice() {
+ testScope.runTest {
+ val dialog = mBluetoothTileDialogDelegate.createDialog()
+ dialog.show()
+ fakeSystemClock.setElapsedRealtime(Long.MAX_VALUE)
+ mBluetoothTileDialogDelegate.onDeviceItemUpdated(
+ dialog,
+ listOf(deviceItem),
+ showSeeAll = false,
+ showPairNewDevice = false
+ )
+
+ val recyclerView = dialog.requireViewById<RecyclerView>(R.id.device_list)
+ val adapter = recyclerView?.adapter as BluetoothTileDialogDelegate.Adapter
+ assertThat(adapter.itemCount).isEqualTo(1)
+ assertThat(adapter.getItem(0).deviceName).isEqualTo(DEVICE_NAME)
+ assertThat(adapter.getItem(0).connectionSummary).isEqualTo(DEVICE_CONNECTION_SUMMARY)
+ assertThat(adapter.getItem(0).iconWithDescription).isEqualTo(icon)
+ }
+ }
+
+ @Test
+ fun testDeviceItemViewHolder_cachedDeviceNotBusy() {
+ deviceItem.isEnabled = true
+
+ val view =
+ LayoutInflater.from(mContext).inflate(R.layout.bluetooth_device_item, null, false)
+ val viewHolder =
+ mBluetoothTileDialogDelegate
+ .Adapter(bluetoothTileDialogCallback)
+ .DeviceItemViewHolder(view)
+ viewHolder.bind(deviceItem, bluetoothTileDialogCallback)
+ val container = view.requireViewById<View>(R.id.bluetooth_device_row)
+
+ assertThat(container).isNotNull()
+ assertThat(container.isEnabled).isTrue()
+ assertThat(container.hasOnClickListeners()).isTrue()
+ }
+
+ @Test
+ fun testDeviceItemViewHolder_cachedDeviceBusy() {
+ deviceItem.isEnabled = false
+
+ val view =
+ LayoutInflater.from(mContext).inflate(R.layout.bluetooth_device_item, null, false)
+ val viewHolder =
+ BluetoothTileDialogDelegate(
+ mContext,
+ uiProperties,
+ CONTENT_HEIGHT,
+ ENABLED,
+ bluetoothTileDialogCallback,
+ {},
+ dispatcher,
+ fakeSystemClock,
+ uiEventLogger,
+ logger,
+ sysuiDialogFactory,
+ LayoutInflater.from(mContext)
+ )
+ .Adapter(bluetoothTileDialogCallback)
+ .DeviceItemViewHolder(view)
+ viewHolder.bind(deviceItem, bluetoothTileDialogCallback)
+ val container = view.requireViewById<View>(R.id.bluetooth_device_row)
+
+ assertThat(container).isNotNull()
+ assertThat(container.isEnabled).isFalse()
+ assertThat(container.hasOnClickListeners()).isTrue()
+ }
+
+ @Test
+ fun testOnDeviceUpdated_hideSeeAll_showPairNew() {
+ testScope.runTest {
+ val dialog = mBluetoothTileDialogDelegate.createDialog()
+ dialog.show()
+ fakeSystemClock.setElapsedRealtime(Long.MAX_VALUE)
+ mBluetoothTileDialogDelegate.onDeviceItemUpdated(
+ dialog,
+ listOf(deviceItem),
+ showSeeAll = false,
+ showPairNewDevice = true
+ )
+
+ val seeAllButton = dialog.requireViewById<View>(R.id.see_all_button)
+ val pairNewButton = dialog.requireViewById<View>(R.id.pair_new_device_button)
+ val recyclerView = dialog.requireViewById<RecyclerView>(R.id.device_list)
+ val adapter = recyclerView?.adapter as BluetoothTileDialogDelegate.Adapter
+ val scrollViewContent = dialog.requireViewById<View>(R.id.scroll_view)
+
+ assertThat(seeAllButton).isNotNull()
+ assertThat(seeAllButton.visibility).isEqualTo(GONE)
+ assertThat(pairNewButton).isNotNull()
+ assertThat(pairNewButton.visibility).isEqualTo(VISIBLE)
+ assertThat(adapter.itemCount).isEqualTo(1)
+ assertThat(scrollViewContent.layoutParams.height).isEqualTo(WRAP_CONTENT)
+ }
+ }
+
+ @Test
+ fun testShowDialog_cachedHeightLargerThanMinHeight_displayFromCachedHeight() {
+ testScope.runTest {
+ val cachedHeight = Int.MAX_VALUE
+ val dialog =
+ BluetoothTileDialogDelegate(
+ mContext,
+ BluetoothTileDialogViewModel.UiProperties.build(ENABLED, ENABLED),
+ cachedHeight,
+ ENABLED,
+ bluetoothTileDialogCallback,
+ {},
+ dispatcher,
+ fakeSystemClock,
+ uiEventLogger,
+ logger,
+ sysuiDialogFactory,
+ LayoutInflater.from(mContext)
+ )
+ .createDialog()
+ dialog.show()
+ assertThat(dialog.requireViewById<View>(R.id.scroll_view).layoutParams.height)
+ .isEqualTo(cachedHeight)
+ }
+ }
+
+ @Test
+ fun testShowDialog_cachedHeightLessThanMinHeight_displayFromUiProperties() {
+ testScope.runTest {
+ val dialog =
+ BluetoothTileDialogDelegate(
+ mContext,
+ BluetoothTileDialogViewModel.UiProperties.build(ENABLED, ENABLED),
+ MATCH_PARENT,
+ ENABLED,
+ bluetoothTileDialogCallback,
+ {},
+ dispatcher,
+ fakeSystemClock,
+ uiEventLogger,
+ logger,
+ sysuiDialogFactory,
+ LayoutInflater.from(mContext)
+ )
+ .createDialog()
+ dialog.show()
+ assertThat(dialog.requireViewById<View>(R.id.scroll_view).layoutParams.height)
+ .isGreaterThan(MATCH_PARENT)
+ }
+ }
+
+ @Test
+ fun testShowDialog_bluetoothEnabled_autoOnToggleGone() {
+ testScope.runTest {
+ val dialog =
+ BluetoothTileDialogDelegate(
+ mContext,
+ BluetoothTileDialogViewModel.UiProperties.build(ENABLED, ENABLED),
+ MATCH_PARENT,
+ ENABLED,
+ bluetoothTileDialogCallback,
+ {},
+ dispatcher,
+ fakeSystemClock,
+ uiEventLogger,
+ logger,
+ sysuiDialogFactory,
+ LayoutInflater.from(mContext)
+ )
+ .createDialog()
+ dialog.show()
+ assertThat(
+ dialog.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/BluetoothTileDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogTest.kt
deleted file mode 100644
index 70b0417..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogTest.kt
+++ /dev/null
@@ -1,330 +0,0 @@
-/*
- * 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.graphics.drawable.Drawable
-import android.testing.AndroidTestingRunner
-import android.testing.TestableLooper
-import android.view.LayoutInflater
-import android.view.View
-import android.view.View.GONE
-import android.view.View.VISIBLE
-import android.view.ViewGroup.LayoutParams.MATCH_PARENT
-import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
-import androidx.recyclerview.widget.LinearLayoutManager
-import androidx.recyclerview.widget.RecyclerView
-import androidx.test.filters.SmallTest
-import com.android.internal.logging.UiEventLogger
-import com.android.settingslib.bluetooth.CachedBluetoothDevice
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.res.R
-import com.android.systemui.util.time.FakeSystemClock
-import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.CoroutineDispatcher
-import kotlinx.coroutines.test.TestCoroutineScheduler
-import kotlinx.coroutines.test.TestScope
-import kotlinx.coroutines.test.UnconfinedTestDispatcher
-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.Mock
-import org.mockito.Mockito.`when`
-import org.mockito.junit.MockitoJUnit
-import org.mockito.junit.MockitoRule
-
-@SmallTest
-@RunWith(AndroidTestingRunner::class)
-@TestableLooper.RunWithLooper(setAsMainLooper = true)
-class BluetoothTileDialogTest : SysuiTestCase() {
- companion object {
- const val DEVICE_NAME = "device"
- const val DEVICE_CONNECTION_SUMMARY = "active"
- const val ENABLED = true
- const val CONTENT_HEIGHT = WRAP_CONTENT
- }
-
- @get:Rule val mockitoRule: MockitoRule = MockitoJUnit.rule()
-
- @Mock private lateinit var cachedBluetoothDevice: CachedBluetoothDevice
-
- @Mock private lateinit var bluetoothTileDialogCallback: BluetoothTileDialogCallback
-
- @Mock private lateinit var drawable: Drawable
-
- @Mock private lateinit var uiEventLogger: UiEventLogger
-
- @Mock private lateinit var logger: BluetoothTileDialogLogger
-
- private val uiProperties =
- BluetoothTileDialogViewModel.UiProperties.build(
- isBluetoothEnabled = ENABLED,
- isAutoOnToggleFeatureAvailable = ENABLED
- )
-
- private val fakeSystemClock = FakeSystemClock()
-
- private lateinit var scheduler: TestCoroutineScheduler
- private lateinit var dispatcher: CoroutineDispatcher
- private lateinit var testScope: TestScope
- private lateinit var icon: Pair<Drawable, String>
- private lateinit var bluetoothTileDialog: BluetoothTileDialog
- private lateinit var deviceItem: DeviceItem
-
- @Before
- fun setUp() {
- scheduler = TestCoroutineScheduler()
- dispatcher = UnconfinedTestDispatcher(scheduler)
- testScope = TestScope(dispatcher)
- bluetoothTileDialog =
- BluetoothTileDialog(
- ENABLED,
- uiProperties,
- CONTENT_HEIGHT,
- bluetoothTileDialogCallback,
- dispatcher,
- fakeSystemClock,
- uiEventLogger,
- logger,
- mContext
- )
- icon = Pair(drawable, DEVICE_NAME)
- deviceItem =
- DeviceItem(
- type = DeviceItemType.AVAILABLE_MEDIA_BLUETOOTH_DEVICE,
- cachedBluetoothDevice = cachedBluetoothDevice,
- deviceName = DEVICE_NAME,
- connectionSummary = DEVICE_CONNECTION_SUMMARY,
- iconWithDescription = icon,
- background = null
- )
- `when`(cachedBluetoothDevice.isBusy).thenReturn(false)
- }
-
- @Test
- fun testShowDialog_createRecyclerViewWithAdapter() {
- bluetoothTileDialog.show()
-
- val recyclerView = bluetoothTileDialog.requireViewById<RecyclerView>(R.id.device_list)
-
- assertThat(bluetoothTileDialog.isShowing).isTrue()
- assertThat(recyclerView).isNotNull()
- assertThat(recyclerView.visibility).isEqualTo(VISIBLE)
- assertThat(recyclerView.adapter).isNotNull()
- assertThat(recyclerView.layoutManager is LinearLayoutManager).isTrue()
- }
-
- @Test
- fun testShowDialog_displayBluetoothDevice() {
- testScope.runTest {
- bluetoothTileDialog =
- BluetoothTileDialog(
- ENABLED,
- uiProperties,
- CONTENT_HEIGHT,
- bluetoothTileDialogCallback,
- dispatcher,
- fakeSystemClock,
- uiEventLogger,
- logger,
- mContext
- )
- bluetoothTileDialog.show()
- fakeSystemClock.setElapsedRealtime(Long.MAX_VALUE)
- bluetoothTileDialog.onDeviceItemUpdated(
- listOf(deviceItem),
- showSeeAll = false,
- showPairNewDevice = false
- )
-
- val recyclerView = bluetoothTileDialog.requireViewById<RecyclerView>(R.id.device_list)
- val adapter = recyclerView.adapter as BluetoothTileDialog.Adapter
- assertThat(adapter.itemCount).isEqualTo(1)
- assertThat(adapter.getItem(0).deviceName).isEqualTo(DEVICE_NAME)
- assertThat(adapter.getItem(0).connectionSummary).isEqualTo(DEVICE_CONNECTION_SUMMARY)
- assertThat(adapter.getItem(0).iconWithDescription).isEqualTo(icon)
- }
- }
-
- @Test
- fun testDeviceItemViewHolder_cachedDeviceNotBusy() {
- deviceItem.isEnabled = true
-
- val view =
- LayoutInflater.from(mContext).inflate(R.layout.bluetooth_device_item, null, false)
- val viewHolder =
- BluetoothTileDialog(
- ENABLED,
- uiProperties,
- CONTENT_HEIGHT,
- bluetoothTileDialogCallback,
- dispatcher,
- fakeSystemClock,
- uiEventLogger,
- logger,
- mContext
- )
- .Adapter(bluetoothTileDialogCallback)
- .DeviceItemViewHolder(view)
- viewHolder.bind(deviceItem, bluetoothTileDialogCallback)
- val container = view.requireViewById<View>(R.id.bluetooth_device_row)
-
- assertThat(container).isNotNull()
- assertThat(container.isEnabled).isTrue()
- assertThat(container.hasOnClickListeners()).isTrue()
- }
-
- @Test
- fun testDeviceItemViewHolder_cachedDeviceBusy() {
- deviceItem.isEnabled = false
-
- val view =
- LayoutInflater.from(mContext).inflate(R.layout.bluetooth_device_item, null, false)
- val viewHolder =
- BluetoothTileDialog(
- ENABLED,
- uiProperties,
- CONTENT_HEIGHT,
- bluetoothTileDialogCallback,
- dispatcher,
- fakeSystemClock,
- uiEventLogger,
- logger,
- mContext
- )
- .Adapter(bluetoothTileDialogCallback)
- .DeviceItemViewHolder(view)
- viewHolder.bind(deviceItem, bluetoothTileDialogCallback)
- val container = view.requireViewById<View>(R.id.bluetooth_device_row)
-
- assertThat(container).isNotNull()
- assertThat(container.isEnabled).isFalse()
- assertThat(container.hasOnClickListeners()).isTrue()
- }
-
- @Test
- fun testOnDeviceUpdated_hideSeeAll_showPairNew() {
- testScope.runTest {
- bluetoothTileDialog =
- BluetoothTileDialog(
- ENABLED,
- uiProperties,
- CONTENT_HEIGHT,
- bluetoothTileDialogCallback,
- dispatcher,
- fakeSystemClock,
- uiEventLogger,
- logger,
- mContext
- )
- bluetoothTileDialog.show()
- fakeSystemClock.setElapsedRealtime(Long.MAX_VALUE)
- bluetoothTileDialog.onDeviceItemUpdated(
- listOf(deviceItem),
- showSeeAll = false,
- showPairNewDevice = true
- )
-
- val seeAllButton = bluetoothTileDialog.requireViewById<View>(R.id.see_all_button)
- val pairNewButton =
- bluetoothTileDialog.requireViewById<View>(R.id.pair_new_device_button)
- val recyclerView = bluetoothTileDialog.requireViewById<RecyclerView>(R.id.device_list)
- val adapter = recyclerView.adapter as BluetoothTileDialog.Adapter
- val scrollViewContent = bluetoothTileDialog.requireViewById<View>(R.id.scroll_view)
-
- assertThat(seeAllButton).isNotNull()
- assertThat(seeAllButton.visibility).isEqualTo(GONE)
- assertThat(pairNewButton).isNotNull()
- assertThat(pairNewButton.visibility).isEqualTo(VISIBLE)
- assertThat(adapter.itemCount).isEqualTo(1)
- assertThat(scrollViewContent.layoutParams.height).isEqualTo(WRAP_CONTENT)
- }
- }
-
- @Test
- 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,
- uiProperties,
- MATCH_PARENT,
- bluetoothTileDialogCallback,
- dispatcher,
- fakeSystemClock,
- uiEventLogger,
- logger,
- mContext
- )
- bluetoothTileDialog.show()
- assertThat(
- bluetoothTileDialog.requireViewById<View>(R.id.scroll_view).layoutParams.height
- )
- .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 cb9f4b4..39e2413 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
@@ -16,7 +16,6 @@
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
@@ -31,10 +30,14 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.DialogTransitionAnimator
import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.statusbar.phone.SystemUIDialog
import com.android.systemui.user.data.repository.FakeUserRepository
+import com.android.systemui.util.FakeSharedPreferences
import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.kotlin.getMutableStateFlow
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.nullable
+import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.settings.FakeSettings
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
@@ -50,12 +53,12 @@
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mock
import org.mockito.Mockito.anyBoolean
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when`
import org.mockito.junit.MockitoJUnit
import org.mockito.junit.MockitoRule
@@ -84,9 +87,15 @@
@Mock private lateinit var uiEventLogger: UiEventLogger
- @Mock private lateinit var logger: BluetoothTileDialogLogger
+ @Mock
+ private lateinit var mBluetoothTileDialogDelegateDelegateFactory:
+ BluetoothTileDialogDelegate.Factory
- @Mock private lateinit var sharedPreferences: SharedPreferences
+ @Mock private lateinit var bluetoothTileDialogDelegate: BluetoothTileDialogDelegate
+
+ @Mock private lateinit var sysuiDialog: SystemUIDialog
+
+ private val sharedPreferences = FakeSharedPreferences()
private lateinit var scheduler: TestCoroutineScheduler
private lateinit var dispatcher: CoroutineDispatcher
@@ -123,20 +132,38 @@
),
mDialogTransitionAnimator,
activityStarter,
- fakeSystemClock,
uiEventLogger,
- logger,
testScope.backgroundScope,
dispatcher,
dispatcher,
sharedPreferences,
+ mBluetoothTileDialogDelegateDelegateFactory
)
- `when`(deviceItemInteractor.deviceItemUpdate).thenReturn(MutableSharedFlow())
- `when`(bluetoothStateInteractor.bluetoothStateUpdate)
+ whenever(deviceItemInteractor.deviceItemUpdate).thenReturn(MutableSharedFlow())
+ whenever(bluetoothStateInteractor.bluetoothStateUpdate)
.thenReturn(MutableStateFlow(null).asStateFlow())
- `when`(deviceItemInteractor.deviceItemUpdateRequest)
+ whenever(deviceItemInteractor.deviceItemUpdateRequest)
.thenReturn(MutableStateFlow(Unit).asStateFlow())
- `when`(bluetoothStateInteractor.isBluetoothEnabled).thenReturn(true)
+ whenever(bluetoothStateInteractor.isBluetoothEnabled).thenReturn(true)
+ whenever(
+ mBluetoothTileDialogDelegateDelegateFactory.create(
+ any(),
+ any(),
+ anyInt(),
+ ArgumentMatchers.anyBoolean(),
+ any(),
+ any()
+ )
+ )
+ .thenReturn(bluetoothTileDialogDelegate)
+ whenever(bluetoothTileDialogDelegate.createDialog()).thenReturn(sysuiDialog)
+ whenever(bluetoothTileDialogDelegate.bluetoothStateToggle)
+ .thenReturn(getMutableStateFlow(false))
+ whenever(bluetoothTileDialogDelegate.deviceItemClick)
+ .thenReturn(getMutableStateFlow(deviceItem))
+ whenever(bluetoothTileDialogDelegate.contentHeight).thenReturn(getMutableStateFlow(0))
+ whenever(bluetoothTileDialogDelegate.bluetoothAutoOnToggle)
+ .thenReturn(getMutableStateFlow(false))
}
@Test
@@ -145,7 +172,6 @@
bluetoothTileDialogViewModel.showDialog(context, null)
verify(mDialogTransitionAnimator, never()).showFromView(any(), any(), any(), any())
- verify(uiEventLogger).log(BluetoothTileDialogUiEvent.BLUETOOTH_TILE_DIALOG_SHOWN)
}
}
@@ -191,7 +217,7 @@
@Test
fun testStartSettingsActivity_activityLaunched_dialogDismissed() {
testScope.runTest {
- `when`(deviceItem.cachedBluetoothDevice).thenReturn(cachedBluetoothDevice)
+ whenever(deviceItem.cachedBluetoothDevice).thenReturn(cachedBluetoothDevice)
bluetoothTileDialogViewModel.showDialog(context, null)
val clickedView = View(context)