Merge "Create BluetoothDetailsViewModel and embed bluetooth xml dialog in it." into main
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorImplTest.kt
index 165ff7b..090e2e9 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorImplTest.kt
@@ -30,6 +30,7 @@
 import com.android.systemui.dump.nano.SystemUIProtoDump
 import com.android.systemui.plugins.qs.QSTile
 import com.android.systemui.plugins.qs.QSTile.BooleanState
+import com.android.systemui.plugins.qs.TileDetailsViewModel
 import com.android.systemui.qs.FakeQSFactory
 import com.android.systemui.qs.FakeQSTile
 import com.android.systemui.qs.external.CustomTile
@@ -154,7 +155,7 @@
                     TileSpec.create("e"),
                     CUSTOM_TILE_SPEC,
                     TileSpec.create("d"),
-                    TileSpec.create("non_existent")
+                    TileSpec.create("non_existent"),
                 )
             tileSpecRepository.setTiles(USER_INFO_0.id, specs)
 
@@ -190,11 +191,7 @@
     @Test
     fun logTileCreated() =
         testScope.runTest(USER_INFO_0) {
-            val specs =
-                listOf(
-                    TileSpec.create("a"),
-                    CUSTOM_TILE_SPEC,
-                )
+            val specs = listOf(TileSpec.create("a"), CUSTOM_TILE_SPEC)
             tileSpecRepository.setTiles(USER_INFO_0.id, specs)
             runCurrent()
 
@@ -204,10 +201,7 @@
     @Test
     fun logTileNotFoundInFactory() =
         testScope.runTest(USER_INFO_0) {
-            val specs =
-                listOf(
-                    TileSpec.create("non_existing"),
-                )
+            val specs = listOf(TileSpec.create("non_existing"))
             tileSpecRepository.setTiles(USER_INFO_0.id, specs)
             runCurrent()
 
@@ -218,10 +212,7 @@
     @Test
     fun tileNotAvailableDestroyed_logged() =
         testScope.runTest(USER_INFO_0) {
-            val specs =
-                listOf(
-                    TileSpec.create("e"),
-                )
+            val specs = listOf(TileSpec.create("e"))
             tileSpecRepository.setTiles(USER_INFO_0.id, specs)
             runCurrent()
 
@@ -229,7 +220,7 @@
             verify(logger)
                 .logTileDestroyed(
                     specs[0],
-                    QSPipelineLogger.TileDestroyedReason.NEW_TILE_NOT_AVAILABLE
+                    QSPipelineLogger.TileDestroyedReason.NEW_TILE_NOT_AVAILABLE,
                 )
         }
 
@@ -238,11 +229,7 @@
         testScope.runTest(USER_INFO_0) {
             val tiles by collectLastValue(tileSpecRepository.tilesSpecs(USER_INFO_0.id))
 
-            val specs =
-                listOf(
-                    TileSpec.create("a"),
-                    TileSpec.create("e"),
-                )
+            val specs = listOf(TileSpec.create("a"), TileSpec.create("e"))
             tileSpecRepository.setTiles(USER_INFO_0.id, specs)
 
             assertThat(tiles).isEqualTo(listOf(TileSpec.create("a")))
@@ -266,10 +253,7 @@
         testScope.runTest(USER_INFO_0) {
             val tiles by collectLastValue(underTest.currentTiles)
 
-            val specs =
-                listOf(
-                    TileSpec.create("a"),
-                )
+            val specs = listOf(TileSpec.create("a"))
 
             tileSpecRepository.setTiles(USER_INFO_0.id, specs)
             val originalTileA = tiles!![0].tile
@@ -299,7 +283,7 @@
             verify(logger)
                 .logTileDestroyed(
                     TileSpec.create("c"),
-                    QSPipelineLogger.TileDestroyedReason.TILE_REMOVED
+                    QSPipelineLogger.TileDestroyedReason.TILE_REMOVED,
                 )
         }
 
@@ -325,7 +309,7 @@
             verify(logger)
                 .logTileDestroyed(
                     TileSpec.create("a"),
-                    QSPipelineLogger.TileDestroyedReason.EXISTING_TILE_NOT_AVAILABLE
+                    QSPipelineLogger.TileDestroyedReason.EXISTING_TILE_NOT_AVAILABLE,
                 )
 
             assertThat(tiles?.size).isEqualTo(1)
@@ -370,7 +354,7 @@
             verify(logger)
                 .logTileDestroyed(
                     specs0[0],
-                    QSPipelineLogger.TileDestroyedReason.TILE_NOT_PRESENT_IN_NEW_USER
+                    QSPipelineLogger.TileDestroyedReason.TILE_NOT_PRESENT_IN_NEW_USER,
                 )
         }
 
@@ -418,21 +402,12 @@
         testScope.runTest(USER_INFO_0) {
             val tiles by collectLastValue(tileSpecRepository.tilesSpecs(USER_INFO_0.id))
             val spec = TileSpec.create("a")
-            val currentSpecs =
-                listOf(
-                    TileSpec.create("b"),
-                    TileSpec.create("c"),
-                )
+            val currentSpecs = listOf(TileSpec.create("b"), TileSpec.create("c"))
             tileSpecRepository.setTiles(USER_INFO_0.id, currentSpecs)
 
             underTest.addTile(spec, position = 1)
 
-            val expectedSpecs =
-                listOf(
-                    TileSpec.create("b"),
-                    spec,
-                    TileSpec.create("c"),
-                )
+            val expectedSpecs = listOf(TileSpec.create("b"), spec, TileSpec.create("c"))
             assertThat(tiles).isEqualTo(expectedSpecs)
         }
 
@@ -442,11 +417,7 @@
             val tiles0 by collectLastValue(tileSpecRepository.tilesSpecs(USER_INFO_0.id))
             val tiles1 by collectLastValue(tileSpecRepository.tilesSpecs(USER_INFO_1.id))
             val spec = TileSpec.create("a")
-            val currentSpecs =
-                listOf(
-                    TileSpec.create("b"),
-                    TileSpec.create("c"),
-                )
+            val currentSpecs = listOf(TileSpec.create("b"), TileSpec.create("c"))
             tileSpecRepository.setTiles(USER_INFO_0.id, currentSpecs)
             tileSpecRepository.setTiles(USER_INFO_1.id, currentSpecs)
 
@@ -455,12 +426,7 @@
 
             assertThat(tiles0).isEqualTo(currentSpecs)
 
-            val expectedSpecs =
-                listOf(
-                    TileSpec.create("b"),
-                    spec,
-                    TileSpec.create("c"),
-                )
+            val expectedSpecs = listOf(TileSpec.create("b"), spec, TileSpec.create("c"))
             assertThat(tiles1).isEqualTo(expectedSpecs)
         }
 
@@ -515,11 +481,7 @@
             val tiles0 by collectLastValue(tileSpecRepository.tilesSpecs(USER_INFO_0.id))
             val tiles1 by collectLastValue(tileSpecRepository.tilesSpecs(USER_INFO_1.id))
             val currentSpecs =
-                listOf(
-                    TileSpec.create("a"),
-                    TileSpec.create("b"),
-                    TileSpec.create("c"),
-                )
+                listOf(TileSpec.create("a"), TileSpec.create("b"), TileSpec.create("c"))
             tileSpecRepository.setTiles(USER_INFO_0.id, currentSpecs)
             tileSpecRepository.setTiles(USER_INFO_1.id, currentSpecs)
 
@@ -557,11 +519,7 @@
             tileSpecRepository.setTiles(USER_INFO_0.id, currentSpecs)
             runCurrent()
 
-            val newSpecs =
-                listOf(
-                    otherCustomTileSpec,
-                    TileSpec.create("a"),
-                )
+            val newSpecs = listOf(otherCustomTileSpec, TileSpec.create("a"))
 
             underTest.setTiles(newSpecs)
             runCurrent()
@@ -615,7 +573,7 @@
 
             tileSpecRepository.setTiles(
                 USER_INFO_0.id,
-                listOf(TileSpec.create("a"), CUSTOM_TILE_SPEC)
+                listOf(TileSpec.create("a"), CUSTOM_TILE_SPEC),
             )
             val newTileA = tiles!![0].tile
             assertThat(tileA).isSameInstanceAs(newTileA)
@@ -650,7 +608,7 @@
 
             installedTilesPackageRepository.setInstalledPackagesForUser(
                 USER_INFO_0.id,
-                setOf(TEST_COMPONENT)
+                setOf(TEST_COMPONENT),
             )
 
             assertThat(tiles!!.size).isEqualTo(3)
@@ -676,10 +634,7 @@
     @Test
     fun changeInPackagesTiles_doesntTriggerUserChange_logged() =
         testScope.runTest(USER_INFO_0) {
-            val specs =
-                listOf(
-                    TileSpec.create("a"),
-                )
+            val specs = listOf(TileSpec.create("a"))
             tileSpecRepository.setTiles(USER_INFO_0.id, specs)
             runCurrent()
             // Settled on the same list of tiles.
@@ -691,7 +646,6 @@
             verify(logger, never()).logTileUserChanged(TileSpec.create("a"), 0)
         }
 
-
     @Test
     fun getTileDetails() =
         testScope.runTest(USER_INFO_0) {
@@ -711,11 +665,19 @@
             assertThat(tiles!![2].spec).isEqualTo(tileNoDetails)
             (tiles!![2].tile as FakeQSTile).hasDetailsViewModel = false
 
-            assertThat(tiles!![0].tile.detailsViewModel.getTitle()).isEqualTo("a")
-            assertThat(tiles!![1].tile.detailsViewModel.getTitle()).isEqualTo("b")
-            assertThat(tiles!![2].tile.detailsViewModel).isNull()
-        }
+            var currentModel: TileDetailsViewModel? = null
+            val setCurrentModel = { model: TileDetailsViewModel? -> currentModel = model }
+            tiles!![0].tile.getDetailsViewModel(setCurrentModel)
+            assertThat(currentModel?.getTitle()).isEqualTo("a")
 
+            currentModel = null
+            tiles!![1].tile.getDetailsViewModel(setCurrentModel)
+            assertThat(currentModel?.getTitle()).isEqualTo("b")
+
+            currentModel = null
+            tiles!![2].tile.getDetailsViewModel(setCurrentModel)
+            assertThat(currentModel).isNull()
+        }
 
     private fun QSTile.State.fillIn(state: Int, label: CharSequence, secondaryLabel: CharSequence) {
         this.state = state
@@ -745,7 +707,7 @@
                     customTileAddedRepository.setTileAdded(
                         CUSTOM_TILE_SPEC.componentName,
                         currentUser,
-                        true
+                        true,
                     )
                 }
             in VALID_TILES -> FakeQSTile(currentUser, available = spec !in unavailableTiles)
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
index 322da32..56176cf 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
@@ -33,6 +33,7 @@
 import com.android.systemui.plugins.qs.QSTile.State;
 
 import java.util.Objects;
+import java.util.function.Consumer;
 import java.util.function.Supplier;
 
 @ProvidesInterface(version = QSTile.VERSION)
@@ -122,9 +123,32 @@
     boolean isListening();
 
     /**
-     * Return this tile's {@link TileDetailsViewModel} to be used to render the TileDetailsView.
+     * Get this tile's {@link TileDetailsViewModel} through a callback.
+     *
+     * Please only override this method if the tile can't get its {@link TileDetailsViewModel}
+     * synchronously and thus need a callback to defer it.
+     *
+     * @return a boolean indicating whether this tile has a {@link TileDetailsViewModel}. The tile's
+     * {@link TileDetailsViewModel} will be passed to the callback. Please always return true when
+     * overriding this method. Return false will make the tile display its dialog instead of details
+     * view, and it will not wait for the callback to be returned before proceeding to show the
+     * dialog.
      */
-    default TileDetailsViewModel getDetailsViewModel() { return null; }
+    default boolean getDetailsViewModel(Consumer<TileDetailsViewModel> callback) {
+        TileDetailsViewModel tileDetailsViewModel = getDetailsViewModel();
+        callback.accept(tileDetailsViewModel);
+        return tileDetailsViewModel != null;
+    }
+
+    /**
+     * Return this tile's {@link TileDetailsViewModel} to be used to render the TileDetailsView.
+     *
+     * Please only override this method if the tile doesn't need a callback to set its
+     * {@link TileDetailsViewModel}.
+     */
+    default TileDetailsViewModel getDetailsViewModel() {
+        return null;
+    }
 
     @ProvidesInterface(version = Callback.VERSION)
     interface Callback {
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsViewModel.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsViewModel.kt
new file mode 100644
index 0000000..9dd3b6d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsViewModel.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.bluetooth.qsdialog
+
+import android.view.LayoutInflater
+import androidx.compose.foundation.layout.fillMaxHeight
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.viewinterop.AndroidView
+import com.android.systemui.plugins.qs.TileDetailsViewModel
+import com.android.systemui.res.R
+
+class BluetoothDetailsViewModel(onLongClick: () -> Unit) : TileDetailsViewModel() {
+    private val _onLongClick = onLongClick
+
+    @Composable
+    override fun GetContentView() {
+        AndroidView(
+            modifier = Modifier.fillMaxWidth().fillMaxHeight(),
+            factory = { context ->
+                // Inflate with the existing dialog xml layout
+                LayoutInflater.from(context).inflate(R.layout.bluetooth_tile_dialog, null)
+                // TODO: b/378513956 - Implement the bluetooth details view
+            },
+        )
+    }
+
+    override fun clickOnSettingsButton() {
+        _onLongClick()
+    }
+
+    override fun getTitle(): String {
+        // TODO: b/378513956 Update the placeholder text
+        return "Bluetooth"
+    }
+
+    override fun getSubTitle(): String {
+        // TODO: b/378513956 Update the placeholder text
+        return "Tap to connect or disconnect a device"
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/DetailsViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/DetailsViewModel.kt
index d8361f5..03f0297 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/DetailsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/DetailsViewModel.kt
@@ -23,11 +23,9 @@
 import com.android.systemui.qs.pipeline.domain.interactor.CurrentTilesInteractor
 import com.android.systemui.qs.pipeline.shared.TileSpec
 import javax.inject.Inject
-import kotlinx.coroutines.flow.StateFlow
 
 @SysUISingleton
-class DetailsViewModel
-@Inject constructor(val currentTilesInteractor: CurrentTilesInteractor) {
+class DetailsViewModel @Inject constructor(val currentTilesInteractor: CurrentTilesInteractor) {
 
     /**
      * The current active [TileDetailsViewModel]. If it's `null`, it means the qs overlay is not
@@ -38,6 +36,7 @@
 
     /**
      * Update the active [TileDetailsViewModel] to `null`.
+     *
      * @see activeTileDetails
      */
     fun closeDetailedView() {
@@ -45,8 +44,9 @@
     }
 
     /**
-     * Update the active [TileDetailsViewModel] to the `spec`'s corresponding view model.
-     * Return if the [TileDetailsViewModel] is successfully found.
+     * Update the active [TileDetailsViewModel] to the `spec`'s corresponding view model. Return if
+     * the [TileDetailsViewModel] is successfully handled.
+     *
      * @see activeTileDetails
      */
     fun onTileClicked(spec: TileSpec?): Boolean {
@@ -55,11 +55,11 @@
             return false
         }
 
-        _activeTileDetails.value = currentTilesInteractor
-            .currentQSTiles
-            .firstOrNull { it.tileSpec == spec.spec }
-            ?.detailsViewModel
+        val currentTile =
+            currentTilesInteractor.currentQSTiles.firstOrNull { it.tileSpec == spec.spec }
 
-        return _activeTileDetails.value != null
+        return currentTile?.getDetailsViewModel { detailsViewModel ->
+            _activeTileDetails.value = detailsViewModel
+        } ?: false
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index 7eb0aaa..0109e70a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -43,6 +43,7 @@
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
 import com.android.settingslib.satellite.SatelliteDialogUtils;
 import com.android.systemui.animation.Expandable;
+import com.android.systemui.bluetooth.qsdialog.BluetoothDetailsViewModel;
 import com.android.systemui.bluetooth.qsdialog.BluetoothTileDialogViewModel;
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
@@ -51,6 +52,7 @@
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
+import com.android.systemui.plugins.qs.TileDetailsViewModel;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSHost;
 import com.android.systemui.qs.QsEventLogger;
@@ -63,6 +65,7 @@
 
 import java.util.List;
 import java.util.concurrent.Executor;
+import java.util.function.Consumer;
 
 import javax.inject.Inject;
 
@@ -121,6 +124,21 @@
 
     @Override
     protected void handleClick(@Nullable Expandable expandable) {
+        handleClickWithSatelliteCheck(() -> handleClickEvent(expandable));
+    }
+
+    @Override
+    public boolean getDetailsViewModel(Consumer<TileDetailsViewModel> callback) {
+        handleClickWithSatelliteCheck(() ->
+                callback.accept(new BluetoothDetailsViewModel(() -> {
+                    longClick(null);
+                    return null;
+                }))
+        );
+        return true;
+    }
+
+    private void handleClickWithSatelliteCheck(Runnable clickCallback) {
         if (com.android.internal.telephony.flags.Flags.oemEnabledSatelliteFlag()) {
             if (mClickJob != null && !mClickJob.isCompleted()) {
                 return;
@@ -130,12 +148,12 @@
                         if (!isAllowClick) {
                             return null;
                         }
-                        handleClickEvent(expandable);
+                        clickCallback.run();
                         return null;
                     });
             return;
         }
-        handleClickEvent(expandable);
+        clickCallback.run();
     }
 
     private void handleClickEvent(@Nullable Expandable expandable) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt
index d8d6f2e9..330b887 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt
@@ -4,6 +4,8 @@
 import android.os.Handler
 import android.os.Looper
 import android.os.UserManager
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
 import android.platform.test.flag.junit.FlagsParameterization
 import android.platform.test.flag.junit.FlagsParameterization.allCombinationsOf
 import android.testing.TestableLooper
@@ -20,10 +22,12 @@
 import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.plugins.FalsingManager
 import com.android.systemui.plugins.qs.QSTile
+import com.android.systemui.plugins.qs.TileDetailsViewModel
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.qs.QSHost
 import com.android.systemui.qs.QsEventLogger
 import com.android.systemui.qs.flags.QSComposeFragment
+import com.android.systemui.qs.flags.QsDetailedView
 import com.android.systemui.qs.flags.QsInCompose.isEnabled
 import com.android.systemui.qs.logging.QSLogger
 import com.android.systemui.qs.tileimpl.QSTileImpl
@@ -35,6 +39,7 @@
 import com.android.systemui.util.mockito.mock
 import com.android.systemui.util.mockito.whenever
 import com.google.common.truth.Truth.assertThat
+import kotlin.test.assertTrue
 import kotlinx.coroutines.Job
 import org.junit.After
 import org.junit.Before
@@ -199,6 +204,7 @@
     }
 
     @Test
+    @DisableFlags(QsDetailedView.FLAG_NAME)
     fun handleClick_hasSatelliteFeatureButNoQsTileDialogAndClickIsProcessing_doNothing() {
         mSetFlagsRule.enableFlags(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
         `when`(featureFlags.isEnabled(com.android.systemui.flags.Flags.BLUETOOTH_QS_TILE_DIALOG))
@@ -212,6 +218,7 @@
     }
 
     @Test
+    @DisableFlags(QsDetailedView.FLAG_NAME)
     fun handleClick_noSatelliteFeatureAndNoQsTileDialog_directSetBtEnable() {
         mSetFlagsRule.disableFlags(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
         `when`(featureFlags.isEnabled(com.android.systemui.flags.Flags.BLUETOOTH_QS_TILE_DIALOG))
@@ -223,6 +230,7 @@
     }
 
     @Test
+    @DisableFlags(QsDetailedView.FLAG_NAME)
     fun handleClick_noSatelliteFeatureButHasQsTileDialog_showDialog() {
         mSetFlagsRule.disableFlags(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
         `when`(featureFlags.isEnabled(com.android.systemui.flags.Flags.BLUETOOTH_QS_TILE_DIALOG))
@@ -234,6 +242,35 @@
     }
 
     @Test
+    @EnableFlags(QsDetailedView.FLAG_NAME)
+    fun handleClick_hasSatelliteFeatureAndQsDetailedViewIsEnabledAndClickIsProcessing_doNothing() {
+        mSetFlagsRule.enableFlags(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
+        `when`(featureFlags.isEnabled(com.android.systemui.flags.Flags.BLUETOOTH_QS_TILE_DIALOG))
+            .thenReturn(false)
+        `when`(clickJob.isCompleted).thenReturn(false)
+        tile.mClickJob = clickJob
+        var currentModel: TileDetailsViewModel? = null
+
+        tile.getDetailsViewModel { model: TileDetailsViewModel? -> currentModel = model }
+
+        // Click is not allowed.
+        assertThat(currentModel).isEqualTo(null)
+    }
+
+    @Test
+    @EnableFlags(QsDetailedView.FLAG_NAME)
+    fun handleClick_noSatelliteFeatureAndQsDetailedViewIsEnabled_returnDetailsViewModel() {
+        mSetFlagsRule.disableFlags(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
+        `when`(featureFlags.isEnabled(com.android.systemui.flags.Flags.BLUETOOTH_QS_TILE_DIALOG))
+            .thenReturn(false)
+        var currentModel: TileDetailsViewModel? = null
+
+        tile.getDetailsViewModel { model: TileDetailsViewModel? -> currentModel = model }
+
+        assertTrue(currentModel != null)
+    }
+
+    @Test
     fun testMetadataListener_whenDisconnected_isUnregistered() {
         val state = QSTile.BooleanState()
         val cachedDevice = mock<CachedBluetoothDevice>()
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/FakeQSTile.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/FakeQSTile.kt
index 06822a6..4714969 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/FakeQSTile.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/FakeQSTile.kt
@@ -19,7 +19,6 @@
 import com.android.internal.logging.InstanceId
 import com.android.systemui.animation.Expandable
 import com.android.systemui.plugins.qs.QSTile
-import com.android.systemui.plugins.qs.TileDetailsViewModel
 
 class FakeQSTile(var user: Int, var available: Boolean = true) : QSTile {
     private var tileSpec: String? = null