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

Commit 2af83996 authored by Dave Mankoff's avatar Dave Mankoff Committed by Android (Google) Code Review
Browse files

Merge "Refactor BluetoothTileDialog into BluetoothTileDialogDelegate" into main

parents ed18b0e3 d7418667
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)