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

Commit a76fc627 authored by Chelsea Hao's avatar Chelsea Hao Committed by Android (Google) Code Review
Browse files

Merge "Add shared bluetooth device functions by settings and systemui to settingslib." into main

parents 4fe40c74 61c0185b
Loading
Loading
Loading
Loading
+133 −1
Original line number Original line Diff line number Diff line
@@ -4,9 +4,9 @@ import static com.android.settingslib.widget.AdaptiveOutlineDrawable.ICON_TYPE_A


import android.annotation.SuppressLint;
import android.annotation.SuppressLint;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothCsipSetCoordinator;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothCsipSetCoordinator;
import android.content.Context;
import android.content.Context;
import android.content.Intent;
import android.content.Intent;
import android.content.res.Resources;
import android.content.res.Resources;
@@ -14,6 +14,7 @@ import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Drawable;
import android.media.AudioManager;
import android.net.Uri;
import android.net.Uri;
import android.provider.DeviceConfig;
import android.provider.DeviceConfig;
import android.provider.MediaStore;
import android.provider.MediaStore;
@@ -23,6 +24,7 @@ import android.util.Pair;


import androidx.annotation.DrawableRes;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.annotation.NonNull;
import androidx.annotation.WorkerThread;
import androidx.core.graphics.drawable.IconCompat;
import androidx.core.graphics.drawable.IconCompat;


import com.android.settingslib.R;
import com.android.settingslib.R;
@@ -470,6 +472,136 @@ public class BluetoothUtils {
        return extraTagValue(KEY_HEARABLE_CONTROL_SLICE, data);
        return extraTagValue(KEY_HEARABLE_CONTROL_SLICE, data);
    }
    }


    /**
     * Check if the Bluetooth device is an AvailableMediaBluetoothDevice, which means:
     * 1) currently connected
     * 2) is Hearing Aid or LE Audio
     *    OR
     * 3) connected profile matches currentAudioProfile
     *
     * @param cachedDevice the CachedBluetoothDevice
     * @param audioManager audio manager to get the current audio profile
     * @return if the device is AvailableMediaBluetoothDevice
     */
    @WorkerThread
    public static boolean isAvailableMediaBluetoothDevice(
            CachedBluetoothDevice cachedDevice, AudioManager audioManager) {
        int audioMode = audioManager.getMode();
        int currentAudioProfile;

        if (audioMode == AudioManager.MODE_RINGTONE
                || audioMode == AudioManager.MODE_IN_CALL
                || audioMode == AudioManager.MODE_IN_COMMUNICATION) {
            // in phone call
            currentAudioProfile = BluetoothProfile.HEADSET;
        } else {
            // without phone call
            currentAudioProfile = BluetoothProfile.A2DP;
        }

        boolean isFilterMatched = false;
        if (isDeviceConnected(cachedDevice)) {
            // If device is Hearing Aid or LE Audio, it is compatible with HFP and A2DP.
            // It would show in Available Devices group.
            if (cachedDevice.isConnectedAshaHearingAidDevice()
                    || cachedDevice.isConnectedLeAudioDevice()) {
                Log.d(TAG, "isFilterMatched() device : "
                        + cachedDevice.getName() + ", the profile is connected.");
                return true;
            }
            // According to the current audio profile type,
            // this page will show the bluetooth device that have corresponding profile.
            // For example:
            // If current audio profile is a2dp, show the bluetooth device that have a2dp profile.
            // If current audio profile is headset,
            // show the bluetooth device that have headset profile.
            switch (currentAudioProfile) {
                case BluetoothProfile.A2DP:
                    isFilterMatched = cachedDevice.isConnectedA2dpDevice();
                    break;
                case BluetoothProfile.HEADSET:
                    isFilterMatched = cachedDevice.isConnectedHfpDevice();
                    break;
            }
        }
        return isFilterMatched;
    }

    /**
     * Check if the Bluetooth device is a ConnectedBluetoothDevice, which means:
     * 1) currently connected
     * 2) is not Hearing Aid or LE Audio
     *    AND
     * 3) connected profile does not match currentAudioProfile
     *
     * @param cachedDevice the CachedBluetoothDevice
     * @param audioManager audio manager to get the current audio profile
     * @return if the device is AvailableMediaBluetoothDevice
     */
    @WorkerThread
    public static boolean isConnectedBluetoothDevice(
            CachedBluetoothDevice cachedDevice, AudioManager audioManager) {
        int audioMode = audioManager.getMode();
        int currentAudioProfile;

        if (audioMode == AudioManager.MODE_RINGTONE
                || audioMode == AudioManager.MODE_IN_CALL
                || audioMode == AudioManager.MODE_IN_COMMUNICATION) {
            // in phone call
            currentAudioProfile = BluetoothProfile.HEADSET;
        } else {
            // without phone call
            currentAudioProfile = BluetoothProfile.A2DP;
        }

        boolean isFilterMatched = false;
        if (isDeviceConnected(cachedDevice)) {
            // If device is Hearing Aid or LE Audio, it is compatible with HFP and A2DP.
            // It would not show in Connected Devices group.
            if (cachedDevice.isConnectedAshaHearingAidDevice()
                    || cachedDevice.isConnectedLeAudioDevice()) {
                return false;
            }
            // According to the current audio profile type,
            // this page will show the bluetooth device that doesn't have corresponding profile.
            // For example:
            // If current audio profile is a2dp,
            // show the bluetooth device that doesn't have a2dp profile.
            // If current audio profile is headset,
            // show the bluetooth device that doesn't have headset profile.
            switch (currentAudioProfile) {
                case BluetoothProfile.A2DP:
                    isFilterMatched = !cachedDevice.isConnectedA2dpDevice();
                    break;
                case BluetoothProfile.HEADSET:
                    isFilterMatched = !cachedDevice.isConnectedHfpDevice();
                    break;
            }
        }
        return isFilterMatched;
    }

    /**
     * Check if the Bluetooth device is an active media device
     *
     * @param cachedDevice the CachedBluetoothDevice
     * @return if the Bluetooth device is an active media device
     */
    public static boolean isActiveMediaDevice(CachedBluetoothDevice cachedDevice) {
        return cachedDevice.isActiveDevice(BluetoothProfile.A2DP)
                || cachedDevice.isActiveDevice(BluetoothProfile.HEADSET)
                || cachedDevice.isActiveDevice(BluetoothProfile.HEARING_AID)
                || cachedDevice.isActiveDevice(BluetoothProfile.LE_AUDIO);
    }

    private static boolean isDeviceConnected(CachedBluetoothDevice cachedDevice) {
        if (cachedDevice == null) {
            return false;
        }
        final BluetoothDevice device = cachedDevice.getDevice();
        return device.getBondState() == BluetoothDevice.BOND_BONDED && device.isConnected();
    }

    @SuppressLint("NewApi") // Hidden API made public
    @SuppressLint("NewApi") // Hidden API made public
    private static boolean doesClassMatch(BluetoothClass btClass, int classId) {
    private static boolean doesClassMatch(BluetoothClass btClass, int classId) {
        return btClass.doesClassMatch(classId);
        return btClass.doesClassMatch(classId);
+109 −1
Original line number Original line Diff line number Diff line
@@ -16,7 +16,6 @@
package com.android.settingslib.bluetooth;
package com.android.settingslib.bluetooth;


import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertThat;

import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.when;
@@ -25,6 +24,7 @@ import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Drawable;
import android.media.AudioManager;
import android.net.Uri;
import android.net.Uri;
import android.util.Pair;
import android.util.Pair;


@@ -46,6 +46,8 @@ public class BluetoothUtilsTest {
    private CachedBluetoothDevice mCachedBluetoothDevice;
    private CachedBluetoothDevice mCachedBluetoothDevice;
    @Mock
    @Mock
    private BluetoothDevice mBluetoothDevice;
    private BluetoothDevice mBluetoothDevice;
    @Mock
    private AudioManager mAudioManager;


    private Context mContext;
    private Context mContext;
    private static final String STRING_METADATA = "string_metadata";
    private static final String STRING_METADATA = "string_metadata";
@@ -255,4 +257,110 @@ public class BluetoothUtilsTest {
    public void isAdvancedUntetheredDevice_noMetadata_returnFalse() {
    public void isAdvancedUntetheredDevice_noMetadata_returnFalse() {
        assertThat(BluetoothUtils.isAdvancedUntetheredDevice(mBluetoothDevice)).isEqualTo(false);
        assertThat(BluetoothUtils.isAdvancedUntetheredDevice(mBluetoothDevice)).isEqualTo(false);
    }
    }

    @Test
    public void isAvailableMediaBluetoothDevice_isConnectedLeAudioDevice_returnTrue() {
        when(mCachedBluetoothDevice.isConnectedLeAudioDevice()).thenReturn(true);
        when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
        when(mBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
        when(mBluetoothDevice.isConnected()).thenReturn(true);

        assertThat(BluetoothUtils.isAvailableMediaBluetoothDevice(mCachedBluetoothDevice,
                mAudioManager)).isEqualTo(true);
    }

    @Test
    public void isAvailableMediaBluetoothDevice_isHeadset_isConnectedA2dpDevice_returnFalse() {
        when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_RINGTONE);
        when(mCachedBluetoothDevice.isConnectedA2dpDevice()).thenReturn(true);
        when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
        when(mBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
        when(mBluetoothDevice.isConnected()).thenReturn(true);

        assertThat(BluetoothUtils.isAvailableMediaBluetoothDevice(mCachedBluetoothDevice,
                mAudioManager)).isEqualTo(false);
    }

    @Test
    public void isAvailableMediaBluetoothDevice_isA2dp_isConnectedA2dpDevice_returnTrue() {
        when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_NORMAL);
        when(mCachedBluetoothDevice.isConnectedA2dpDevice()).thenReturn(true);
        when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
        when(mBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
        when(mBluetoothDevice.isConnected()).thenReturn(true);

        assertThat(BluetoothUtils.isAvailableMediaBluetoothDevice(mCachedBluetoothDevice,
                mAudioManager)).isEqualTo(true);
    }

    @Test
    public void isAvailableMediaBluetoothDevice_isHeadset_isConnectedHfpDevice_returnTrue() {
        when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_RINGTONE);
        when(mCachedBluetoothDevice.isConnectedHfpDevice()).thenReturn(true);
        when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
        when(mBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
        when(mBluetoothDevice.isConnected()).thenReturn(true);

        assertThat(BluetoothUtils.isAvailableMediaBluetoothDevice(mCachedBluetoothDevice,
                mAudioManager)).isEqualTo(true);
    }

    @Test
    public void isConnectedBluetoothDevice_isConnectedLeAudioDevice_returnFalse() {
        when(mCachedBluetoothDevice.isConnectedLeAudioDevice()).thenReturn(true);
        when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
        when(mBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
        when(mBluetoothDevice.isConnected()).thenReturn(true);

        assertThat(BluetoothUtils.isConnectedBluetoothDevice(mCachedBluetoothDevice,
                mAudioManager)).isEqualTo(false);
    }

    @Test
    public void isConnectedBluetoothDevice_isHeadset_isConnectedA2dpDevice_returnTrue() {
        when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_RINGTONE);
        when(mCachedBluetoothDevice.isConnectedA2dpDevice()).thenReturn(true);
        when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
        when(mBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
        when(mBluetoothDevice.isConnected()).thenReturn(true);

        assertThat(BluetoothUtils.isConnectedBluetoothDevice(mCachedBluetoothDevice,
                mAudioManager)).isEqualTo(true);
    }

    @Test
    public void isConnectedBluetoothDevice_isA2dp_isConnectedA2dpDevice_returnFalse() {
        when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_NORMAL);
        when(mCachedBluetoothDevice.isConnectedA2dpDevice()).thenReturn(true);
        when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
        when(mBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
        when(mBluetoothDevice.isConnected()).thenReturn(true);

        assertThat(BluetoothUtils.isConnectedBluetoothDevice(mCachedBluetoothDevice,
                mAudioManager)).isEqualTo(false);
    }

    @Test
    public void isConnectedBluetoothDevice_isHeadset_isConnectedHfpDevice_returnFalse() {
        when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_RINGTONE);
        when(mCachedBluetoothDevice.isConnectedHfpDevice()).thenReturn(true);
        when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
        when(mBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
        when(mBluetoothDevice.isConnected()).thenReturn(true);

        assertThat(BluetoothUtils.isConnectedBluetoothDevice(mCachedBluetoothDevice,
                mAudioManager)).isEqualTo(false);
    }

    @Test
    public void isConnectedBluetoothDevice_isNotConnected_returnFalse() {
        when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_RINGTONE);
        when(mCachedBluetoothDevice.isConnectedA2dpDevice()).thenReturn(true);
        when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
        when(mBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
        when(mBluetoothDevice.isConnected()).thenReturn(false);

        assertThat(BluetoothUtils.isConnectedBluetoothDevice(mCachedBluetoothDevice,
                mAudioManager)).isEqualTo(false);
    }
}
}