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

Commit bb4c7541 authored by Srinivas Patibandla's avatar Srinivas Patibandla Committed by Android (Google) Code Review
Browse files

Merge "[Hide DCK Device] Hide DCK BluetoothDevice from QS SysUI" into main

parents e2a2de37 6e3328ed
Loading
Loading
Loading
Loading
+8 −1
Original line number Diff line number Diff line
@@ -44,3 +44,10 @@ flag {
  description: "Gates whether to enable LE audio private broadcast sharing via QR code"
  bug: "308368124"
}

flag {
  name: "enable_hide_exclusively_managed_bluetooth_device"
  namespace: "dck_framework"
  description: "Hide exclusively managed Bluetooth devices in BT settings menu."
  bug: "324475542"
}
+22 −2
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.content.Context
import android.media.AudioManager
import com.android.settingslib.bluetooth.BluetoothUtils
import com.android.settingslib.bluetooth.CachedBluetoothDevice
import com.android.settingslib.flags.Flags
import com.android.systemui.res.R

private val backgroundOn = R.drawable.settingslib_switch_bar_bg_on
@@ -36,6 +37,7 @@ private val actionAccessibilityLabelDisconnect =
/** Factories to create different types of Bluetooth device items from CachedBluetoothDevice. */
internal abstract class DeviceItemFactory {
    abstract fun isFilterMatched(
        context: Context,
        cachedDevice: CachedBluetoothDevice,
        audioManager: AudioManager?
    ): Boolean
@@ -45,6 +47,7 @@ internal abstract class DeviceItemFactory {

internal class ActiveMediaDeviceItemFactory : DeviceItemFactory() {
    override fun isFilterMatched(
        context: Context,
        cachedDevice: CachedBluetoothDevice,
        audioManager: AudioManager?
    ): Boolean {
@@ -71,6 +74,7 @@ internal class ActiveMediaDeviceItemFactory : DeviceItemFactory() {

internal class AvailableMediaDeviceItemFactory : DeviceItemFactory() {
    override fun isFilterMatched(
        context: Context,
        cachedDevice: CachedBluetoothDevice,
        audioManager: AudioManager?
    ): Boolean {
@@ -99,10 +103,18 @@ internal class AvailableMediaDeviceItemFactory : DeviceItemFactory() {

internal class ConnectedDeviceItemFactory : DeviceItemFactory() {
    override fun isFilterMatched(
        context: Context,
        cachedDevice: CachedBluetoothDevice,
        audioManager: AudioManager?
    ): Boolean {
        return BluetoothUtils.isConnectedBluetoothDevice(cachedDevice, audioManager)
        return if (Flags.enableHideExclusivelyManagedBluetoothDevice()) {
            !BluetoothUtils.isExclusivelyManagedBluetoothDevice(
                context,
                cachedDevice.getDevice()
            ) && BluetoothUtils.isConnectedBluetoothDevice(cachedDevice, audioManager)
        } else {
            BluetoothUtils.isConnectedBluetoothDevice(cachedDevice, audioManager)
        }
    }

    override fun create(context: Context, cachedDevice: CachedBluetoothDevice): DeviceItem {
@@ -125,10 +137,18 @@ internal class ConnectedDeviceItemFactory : DeviceItemFactory() {

internal class SavedDeviceItemFactory : DeviceItemFactory() {
    override fun isFilterMatched(
        context: Context,
        cachedDevice: CachedBluetoothDevice,
        audioManager: AudioManager?
    ): Boolean {
        return cachedDevice.bondState == BluetoothDevice.BOND_BONDED && !cachedDevice.isConnected
        return if (Flags.enableHideExclusivelyManagedBluetoothDevice()) {
            !BluetoothUtils.isExclusivelyManagedBluetoothDevice(
                context,
                cachedDevice.getDevice()
            ) && cachedDevice.bondState == BluetoothDevice.BOND_BONDED && !cachedDevice.isConnected
        } else {
            cachedDevice.bondState == BluetoothDevice.BOND_BONDED && !cachedDevice.isConnected
        }
    }

    override fun create(context: Context, cachedDevice: CachedBluetoothDevice): DeviceItem {
+1 −1
Original line number Diff line number Diff line
@@ -133,7 +133,7 @@ constructor(
                bluetoothTileDialogRepository.cachedDevices
                    .mapNotNull { cachedDevice ->
                        deviceItemFactoryList
                            .firstOrNull { it.isFilterMatched(cachedDevice, audioManager) }
                            .firstOrNull { it.isFilterMatched(context, cachedDevice, audioManager) }
                            ?.create(context, cachedDevice)
                    }
                    .sort(displayPriority, bluetoothAdapter?.mostRecentlyConnectedDevices)
+237 −1
Original line number Diff line number Diff line
@@ -16,10 +16,18 @@

package com.android.systemui.qs.tiles.dialog.bluetooth

import android.bluetooth.BluetoothDevice
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.media.AudioManager
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import androidx.test.filters.SmallTest
import com.android.settingslib.bluetooth.BluetoothUtils
import com.android.settingslib.bluetooth.CachedBluetoothDevice
import com.android.settingslib.flags.Flags
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
import org.junit.Before
@@ -35,19 +43,26 @@ import org.mockito.junit.MockitoRule
@RunWith(AndroidTestingRunner::class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
class DeviceItemFactoryTest : SysuiTestCase() {

    @get:Rule val mockitoRule: MockitoRule = MockitoJUnit.rule()

    @Mock private lateinit var cachedDevice: CachedBluetoothDevice
    @Mock private lateinit var bluetoothDevice: BluetoothDevice
    @Mock private lateinit var packageManager: PackageManager

    private val availableMediaDeviceItemFactory = AvailableMediaDeviceItemFactory()
    private val connectedDeviceItemFactory = ConnectedDeviceItemFactory()
    private val savedDeviceItemFactory = SavedDeviceItemFactory()

    private val audioManager = context.getSystemService(AudioManager::class.java)!!

    @Before
    fun setup() {
        `when`(cachedDevice.name).thenReturn(DEVICE_NAME)
        `when`(cachedDevice.address).thenReturn(DEVICE_ADDRESS)
        `when`(cachedDevice.device).thenReturn(bluetoothDevice)
        `when`(cachedDevice.connectionSummary).thenReturn(CONNECTION_SUMMARY)

        context.setMockPackageManager(packageManager)
    }

    @Test
@@ -72,6 +87,225 @@ class DeviceItemFactoryTest : SysuiTestCase() {
        assertThat(deviceItem.background).isNotNull()
    }

    @Test
    @DisableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
    fun testSavedFactory_isFilterMatched_bondedAndNotConnected_returnsTrue() {
        `when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
        `when`(cachedDevice.isConnected).thenReturn(false)

        assertThat(savedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
            .isTrue()
    }

    @Test
    @DisableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
    fun testSavedFactory_isFilterMatched_connected_returnsFalse() {
        `when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
        `when`(cachedDevice.isConnected).thenReturn(true)

        assertThat(savedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
            .isFalse()
    }

    @Test
    @DisableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
    fun testSavedFactory_isFilterMatched_notBonded_returnsFalse() {
        `when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_NONE)
        `when`(cachedDevice.isConnected).thenReturn(false)

        assertThat(savedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
            .isFalse()
    }

    @Test
    @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
    fun testSavedFactory_isFilterMatched_exclusivelyManaged_returnsFalse() {
        val exclusiveManagerName =
            BluetoothUtils.getExclusiveManagers().firstOrNull() ?: FAKE_EXCLUSIVE_MANAGER_NAME
        `when`(bluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER))
            .thenReturn(exclusiveManagerName.toByteArray())
        `when`(packageManager.getPackageInfo(exclusiveManagerName, 0)).thenReturn(PackageInfo())
        `when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
        `when`(cachedDevice.isConnected).thenReturn(false)

        assertThat(savedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
            .isFalse()
    }

    @Test
    @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
    fun testSavedFactory_isFilterMatched_noExclusiveManager_returnsTrue() {
        `when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
        `when`(cachedDevice.isConnected).thenReturn(false)

        assertThat(savedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
            .isTrue()
    }

    @Test
    @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
    fun testSavedFactory_isFilterMatched_notAllowedExclusiveManager_returnsTrue() {
        `when`(bluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER))
            .thenReturn(FAKE_EXCLUSIVE_MANAGER_NAME.toByteArray())
        `when`(packageManager.getPackageInfo(FAKE_EXCLUSIVE_MANAGER_NAME, 0))
            .thenReturn(PackageInfo())
        `when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
        `when`(cachedDevice.isConnected).thenReturn(false)

        assertThat(savedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
            .isTrue()
    }

    @Test
    @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
    fun testSavedFactory_isFilterMatched_uninstalledExclusiveManager_returnsTrue() {
        val exclusiveManagerName =
            BluetoothUtils.getExclusiveManagers().firstOrNull() ?: FAKE_EXCLUSIVE_MANAGER_NAME
        `when`(bluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER))
            .thenReturn(exclusiveManagerName.toByteArray())
        `when`(packageManager.getPackageInfo(exclusiveManagerName, 0))
            .thenThrow(PackageManager.NameNotFoundException("Test!"))
        `when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
        `when`(cachedDevice.isConnected).thenReturn(false)

        assertThat(savedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
            .isTrue()
    }

    @Test
    @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
    fun testSavedFactory_isFilterMatched_notExclusivelyManaged_notBonded_returnsFalse() {
        `when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_NONE)
        `when`(cachedDevice.isConnected).thenReturn(false)

        assertThat(savedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
            .isFalse()
    }

    @Test
    @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
    fun testSavedFactory_isFilterMatched_notExclusivelyManaged_connected_returnsFalse() {
        `when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
        `when`(cachedDevice.isConnected).thenReturn(true)

        assertThat(savedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
            .isFalse()
    }

    @Test
    @DisableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
    fun testConnectedFactory_isFilterMatched_bondedAndConnected_returnsTrue() {
        `when`(bluetoothDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
        `when`(bluetoothDevice.isConnected).thenReturn(true)
        audioManager.setMode(AudioManager.MODE_NORMAL)

        assertThat(connectedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
            .isTrue()
    }

    @Test
    @DisableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
    fun testConnectedFactory_isFilterMatched_notConnected_returnsFalse() {
        `when`(bluetoothDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
        `when`(bluetoothDevice.isConnected).thenReturn(false)
        audioManager.setMode(AudioManager.MODE_NORMAL)

        assertThat(connectedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
            .isFalse()
    }

    @Test
    @DisableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
    fun testConnectedFactory_isFilterMatched_notBonded_returnsFalse() {
        `when`(bluetoothDevice.bondState).thenReturn(BluetoothDevice.BOND_NONE)
        `when`(bluetoothDevice.isConnected).thenReturn(true)
        audioManager.setMode(AudioManager.MODE_NORMAL)

        assertThat(connectedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
            .isFalse()
    }

    @Test
    @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
    fun testConnectedFactory_isFilterMatched_exclusivelyManaged_returnsFalse() {
        val exclusiveManagerName =
            BluetoothUtils.getExclusiveManagers().firstOrNull() ?: FAKE_EXCLUSIVE_MANAGER_NAME
        `when`(bluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER))
            .thenReturn(exclusiveManagerName.toByteArray())
        `when`(packageManager.getPackageInfo(exclusiveManagerName, 0)).thenReturn(PackageInfo())
        `when`(bluetoothDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
        `when`(bluetoothDevice.isConnected).thenReturn(true)
        audioManager.setMode(AudioManager.MODE_NORMAL)

        assertThat(connectedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
            .isFalse()
    }

    @Test
    @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
    fun testConnectedFactory_isFilterMatched_noExclusiveManager_returnsTrue() {
        `when`(bluetoothDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
        `when`(bluetoothDevice.isConnected).thenReturn(true)
        audioManager.setMode(AudioManager.MODE_NORMAL)

        assertThat(connectedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
            .isTrue()
    }

    @Test
    @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
    fun testConnectedFactory_isFilterMatched_notAllowedExclusiveManager_returnsTrue() {
        `when`(bluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER))
            .thenReturn(FAKE_EXCLUSIVE_MANAGER_NAME.toByteArray())
        `when`(packageManager.getPackageInfo(FAKE_EXCLUSIVE_MANAGER_NAME, 0))
            .thenReturn(PackageInfo())
        `when`(bluetoothDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
        `when`(bluetoothDevice.isConnected).thenReturn(true)
        audioManager.setMode(AudioManager.MODE_NORMAL)

        assertThat(connectedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
            .isTrue()
    }

    @Test
    @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
    fun testConnectedFactory_isFilterMatched_uninstalledExclusiveManager_returnsTrue() {
        val exclusiveManagerName =
            BluetoothUtils.getExclusiveManagers().firstOrNull() ?: FAKE_EXCLUSIVE_MANAGER_NAME
        `when`(bluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER))
            .thenReturn(exclusiveManagerName.toByteArray())
        `when`(packageManager.getPackageInfo(exclusiveManagerName, 0))
            .thenThrow(PackageManager.NameNotFoundException("Test!"))
        `when`(bluetoothDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
        `when`(bluetoothDevice.isConnected).thenReturn(true)
        audioManager.setMode(AudioManager.MODE_NORMAL)

        assertThat(connectedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
            .isTrue()
    }

    @Test
    @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
    fun testConnectedFactory_isFilterMatched_notExclusivelyManaged_notBonded_returnsFalse() {
        `when`(bluetoothDevice.bondState).thenReturn(BluetoothDevice.BOND_NONE)
        `when`(bluetoothDevice.isConnected).thenReturn(true)
        audioManager.setMode(AudioManager.MODE_NORMAL)

        assertThat(connectedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
            .isFalse()
    }

    @Test
    @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
    fun testConnectedFactory_isFilterMatched_notExclusivelyManaged_notConnected_returnsFalse() {
        `when`(bluetoothDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
        `when`(bluetoothDevice.isConnected).thenReturn(false)
        audioManager.setMode(AudioManager.MODE_NORMAL)

        assertThat(connectedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
            .isFalse()
    }

    private fun assertDeviceItem(deviceItem: DeviceItem?, deviceItemType: DeviceItemType) {
        assertThat(deviceItem).isNotNull()
        assertThat(deviceItem!!.type).isEqualTo(deviceItemType)
@@ -83,5 +317,7 @@ class DeviceItemFactoryTest : SysuiTestCase() {
    companion object {
        const val DEVICE_NAME = "DeviceName"
        const val CONNECTION_SUMMARY = "ConnectionSummary"
        private const val FAKE_EXCLUSIVE_MANAGER_NAME = "com.fake.name"
        private const val DEVICE_ADDRESS = "04:52:C7:0B:D8:3C"
    }
}
+1 −0
Original line number Diff line number Diff line
@@ -279,6 +279,7 @@ class DeviceItemInteractorTest : SysuiTestCase() {
    ): DeviceItemFactory {
        return object : DeviceItemFactory() {
            override fun isFilterMatched(
                context: Context,
                cachedDevice: CachedBluetoothDevice,
                audioManager: AudioManager?
            ) = isFilterMatchFunc(cachedDevice)