Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d7418667 authored by Dave Mankoff's avatar Dave Mankoff
Browse files

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
parent dac9af85
Loading
Loading
Loading
Loading
+124 −88
Original line number Diff line number Diff line
@@ -37,11 +37,13 @@ import androidx.recyclerview.widget.DiffUtil
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.isActive
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 @@ constructor(

    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

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    @AssistedFactory
    internal interface Factory {
        fun create(
            context: Context,
            initialUiProperties: BluetoothTileDialogViewModel.UiProperties,
            cachedContentHeight: Int,
            bluetoothEnabled: Boolean,
            dialogCallback: BluetoothTileDialogCallback,
            dimissListener: Runnable
        ): BluetoothTileDialogDelegate
    }

    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()
        setupRecyclerView()
        setupToggle(dialog)
        setupRecyclerView(dialog)

        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 @@ constructor(
            }
            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 @@ constructor(
    }

    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 {
    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 @@ constructor(
            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 @@ constructor(
        }
    }

    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 @@ constructor(
        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)
        }

+31 −35
Original line number Diff line number Diff line
@@ -38,13 +38,11 @@ import com.android.systemui.dagger.qualifiers.Application
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 @@ constructor(
    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 @@ constructor(
            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 @@ constructor(
                    .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 @@ constructor(
                // 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 @@ constructor(
                bluetoothStateInteractor.bluetoothStateUpdate
                    .filterNotNull()
                    .onEach {
                        dialog.onBluetoothStateUpdated(
                        dialogDelegate.onBluetoothStateUpdated(
                            dialog,
                            it,
                            UiProperties.build(it, isAutoOnToggleFeatureAvailable())
                        )
@@ -166,20 +166,20 @@ constructor(

                // 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 @@ constructor(
                    // 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 @@ constructor(
            }
    }

    private suspend fun createBluetoothTileDialog(context: Context): BluetoothTileDialog {
    private suspend fun createBluetoothTileDialog(context: Context): BluetoothTileDialogDelegate {
        val cachedContentHeight =
            withContext(backgroundDispatcher) {
                sharedPreferences.getInt(
@@ -215,21 +215,17 @@ constructor(
                )
            }

        return BluetoothTileDialog(
                bluetoothStateInteractor.isBluetoothEnabled,
        return bluetoothDialogDelegateFactory.create(
            context,
            UiProperties.build(
                bluetoothStateInteractor.isBluetoothEnabled,
                isAutoOnToggleFeatureAvailable()
            ),
            cachedContentHeight,
            bluetoothStateInteractor.isBluetoothEnabled,
            this@BluetoothTileDialogViewModel,
                mainDispatcher,
                systemClock,
                uiEventLogger,
                logger,
                context
            { cancelJob() }
        )
            .apply { SystemUIDialog.registerDismissListener(this) { cancelJob() } }
    }

    override fun onDeviceItemGearClicked(deviceItem: DeviceItem, view: View) {
@@ -308,7 +304,7 @@ constructor(
    }
}

internal interface BluetoothTileDialogCallback {
interface BluetoothTileDialogCallback {
    fun onDeviceItemGearClicked(deviceItem: DeviceItem, view: View)
    fun onSeeAllClicked(view: View)
    fun onPairNewDeviceClicked(view: View)
+124 −107

File changed and moved.

Preview size limit exceeded, changes collapsed.

+38 −12
Original line number Diff line number Diff line
@@ -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.settingslib.flags.Flags
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.Before
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 @@ class BluetoothTileDialogViewModelTest : SysuiTestCase() {

    @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 @@ class BluetoothTileDialogViewModelTest : SysuiTestCase() {
                ),
                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 @@ class BluetoothTileDialogViewModelTest : SysuiTestCase() {
            bluetoothTileDialogViewModel.showDialog(context, null)

            verify(mDialogTransitionAnimator, never()).showFromView(any(), any(), any(), any())
            verify(uiEventLogger).log(BluetoothTileDialogUiEvent.BLUETOOTH_TILE_DIALOG_SHOWN)
        }
    }

@@ -191,7 +217,7 @@ class BluetoothTileDialogViewModelTest : SysuiTestCase() {
    @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)