From e7c89d616a30f1f2811dab9cac11c01b2ea59e30 Mon Sep 17 00:00:00 2001 From: SongFerngWang Date: Thu, 10 Mar 2022 23:43:20 +0800 Subject: [PATCH] [LE]Gray out the a2dp and hfp when LeAudio is enabled 1.Gray out the a2dp and hfp when le audio is enabled 2.When the user disables le audio, then the settings turn on the a2dp and hfp 3.When the user enables le audio, then the settings turn off the a2dp and hfp Bug: 218626162 Test: build pass. Change-Id: Ic728749112b0047cac291600b3279b9dedbf0b5a Merged-In: Ic728749112b0047cac291600b3279b9dedbf0b5a --- .../BluetoothDetailsProfilesController.java | 215 +++++++++++++++++- 1 file changed, 207 insertions(+), 8 deletions(-) diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java b/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java index aacf41fbbc9..b57ea928d99 100644 --- a/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java +++ b/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java @@ -16,10 +16,12 @@ package com.android.settings.bluetooth; +import android.bluetooth.BluetoothCsipSetCoordinator; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothProfile; import android.content.Context; import android.text.TextUtils; +import android.util.Log; import androidx.annotation.VisibleForTesting; import androidx.preference.Preference; @@ -31,6 +33,7 @@ import androidx.preference.SwitchPreference; import com.android.settings.R; import com.android.settingslib.bluetooth.A2dpProfile; import com.android.settingslib.bluetooth.CachedBluetoothDevice; +import com.android.settingslib.bluetooth.LeAudioProfile; import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.bluetooth.LocalBluetoothProfile; import com.android.settingslib.bluetooth.LocalBluetoothProfileManager; @@ -39,7 +42,10 @@ import com.android.settingslib.bluetooth.PanProfile; import com.android.settingslib.bluetooth.PbapServerProfile; import com.android.settingslib.core.lifecycle.Lifecycle; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** * This class adds switches for toggling the individual profiles that a Bluetooth device @@ -48,8 +54,11 @@ import java.util.List; public class BluetoothDetailsProfilesController extends BluetoothDetailsController implements Preference.OnPreferenceClickListener, LocalBluetoothProfileManager.ServiceListener { + private static final String TAG = "BtDetailsProfilesCtrl"; + private static final String KEY_PROFILES_GROUP = "bluetooth_profiles"; private static final String KEY_BOTTOM_PREFERENCE = "bottom_preference"; + private static final String HEADSET_CLIENT = "HEADSET_CLIENT"; private static final int ORDINAL = 99; @VisibleForTesting @@ -58,6 +67,9 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll private LocalBluetoothManager mManager; private LocalBluetoothProfileManager mProfileManager; private CachedBluetoothDevice mCachedDevice; + private List mAllOfCachedDevices; + private Map> mProfileDeviceMap = + new HashMap>(); @VisibleForTesting PreferenceCategory mProfilesContainer; @@ -68,6 +80,7 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll mManager = manager; mProfileManager = mManager.getProfileManager(); mCachedDevice = device; + mAllOfCachedDevices = getAllOfCachedBluetoothDevices(); lifecycle.addObserver(this); } @@ -100,11 +113,66 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll /** * Refreshes the state for an existing SwitchPreference for a profile. + * If the LeAudio profile is enabled on the LeAudio devices, then the SwitchPreferences of + * A2dp profile and Hfp profile are graied out. */ private void refreshProfilePreference(SwitchPreference profilePref, LocalBluetoothProfile profile) { BluetoothDevice device = mCachedDevice.getDevice(); - profilePref.setEnabled(!mCachedDevice.isBusy()); + boolean isLeAudioEnabled = false; + if (profile instanceof A2dpProfile || HEADSET_CLIENT.equals(profile.toString())) { + LocalBluetoothProfile leAudio = mProfileManager.getLeAudioProfile(); + if (leAudio != null) { + List leAudioDeviceList = mProfileDeviceMap.get( + leAudio.toString()); + if (leAudioDeviceList != null + && leAudioDeviceList.stream() + .anyMatch(item -> leAudio.isEnabled(item.getDevice()))) { + isLeAudioEnabled = true; + } + } + if (isLeAudioEnabled) { + // If the LeAudio profile is enabled on the LeAudio devices, then the + // SwitchPreferences of A2dp profile and Hfp profile are graied out. + profilePref.setEnabled(false); + } else { + List deviceList = mProfileDeviceMap.get( + profile.toString()); + boolean isBusy = deviceList != null + && deviceList.stream().anyMatch(item -> item.isBusy()); + profilePref.setEnabled(!isBusy); + } + } else if (profile instanceof LeAudioProfile) { + List leAudioDeviceList = mProfileDeviceMap.get( + profile.toString()); + boolean isLeAudioProfileEnable = + leAudioDeviceList != null && leAudioDeviceList.stream().anyMatch( + item -> profile.isEnabled(item.getDevice())); + boolean isBusy = leAudioDeviceList != null + && leAudioDeviceList.stream().anyMatch(item -> item.isBusy()); + if (isLeAudioProfileEnable && !isBusy) { + LocalBluetoothProfile a2dp = mProfileManager.getA2dpProfile(); + LocalBluetoothProfile hfp = mProfileManager.getHfpClientProfile(); + // If the LeAudio profile is enabled on the LeAudio devices, then the + // SwitchPreferences of A2dp profile and Hfp profile are graied out. + if (a2dp != null) { + SwitchPreference pref = mProfilesContainer.findPreference(a2dp.toString()); + if (pref != null) { + pref.setEnabled(false); + } + } + if (hfp != null) { + SwitchPreference pref = mProfilesContainer.findPreference(hfp.toString()); + if (pref != null) { + pref.setEnabled(false); + } + } + } + profilePref.setEnabled(!isBusy); + } else { + profilePref.setEnabled(!mCachedDevice.isBusy()); + } + if (profile instanceof MapProfile) { profilePref.setChecked(device.getMessageAccessPermission() == BluetoothDevice.ACCESS_ALLOWED); @@ -127,7 +195,7 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll highQualityPref.setVisible(true); highQualityPref.setTitle(a2dp.getHighQualityAudioOptionLabel(device)); highQualityPref.setChecked(a2dp.isHighQualityAudioEnabled(device)); - highQualityPref.setEnabled(!mCachedDevice.isBusy()); + highQualityPref.setEnabled(!mCachedDevice.isBusy() && !isLeAudioEnabled); } else { highQualityPref.setVisible(false); } @@ -148,6 +216,12 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll if (profile instanceof MapProfile) { bluetoothDevice.setMessageAccessPermission(BluetoothDevice.ACCESS_ALLOWED); } + + if (profile instanceof LeAudioProfile) { + enableLeAudioProfile(profile); + return; + } + profile.setEnabled(bluetoothDevice, true); } @@ -155,8 +229,14 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll * Helper method to disable a profile for a device */ private void disableProfile(LocalBluetoothProfile profile) { + if (profile instanceof LeAudioProfile) { + disableLeAudioProfile(profile); + return; + } + final BluetoothDevice bluetoothDevice = mCachedDevice.getDevice(); profile.setEnabled(bluetoothDevice, false); + if (profile instanceof MapProfile) { bluetoothDevice.setMessageAccessPermission(BluetoothDevice.ACCESS_REJECTED); } else if (profile instanceof PbapServerProfile) { @@ -190,14 +270,33 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll return true; } - /** * Helper to get the list of connectable and special profiles. */ private List getProfiles() { - List result = mCachedDevice.getConnectableProfiles(); - final BluetoothDevice device = mCachedDevice.getDevice(); + List result = new ArrayList(); + mProfileDeviceMap.clear(); + if (mAllOfCachedDevices == null || mAllOfCachedDevices.isEmpty()) { + return result; + } + for (CachedBluetoothDevice cachedItem : mAllOfCachedDevices) { + List tmpResult = cachedItem.getConnectableProfiles(); + for (LocalBluetoothProfile profile : tmpResult) { + if (mProfileDeviceMap.containsKey(profile.toString())) { + mProfileDeviceMap.get(profile.toString()).add(cachedItem); + Log.d(TAG, "getProfiles: " + profile.toString() + " add device " + + cachedItem.getDevice().getAnonymizedAddress()); + } else { + List tmpCachedDeviceList = + new ArrayList(); + tmpCachedDeviceList.add(cachedItem); + mProfileDeviceMap.put(profile.toString(), tmpCachedDeviceList); + result.add(profile); + } + } + } + final BluetoothDevice device = mCachedDevice.getDevice(); final int pbapPermission = device.getPhonebookAccessPermission(); // Only provide PBAP cabability if the client device has requested PBAP. if (pbapPermission != BluetoothDevice.ACCESS_UNKNOWN) { @@ -210,10 +309,93 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll if (mapPermission != BluetoothDevice.ACCESS_UNKNOWN) { result.add(mapProfile); } - + Log.d(TAG, "getProfiles:result:" + result); return result; } + private List getAllOfCachedBluetoothDevices() { + List cachedBluetoothDevices = new ArrayList<>(); + if (mCachedDevice == null) { + return cachedBluetoothDevices; + } + cachedBluetoothDevices.add(mCachedDevice); + if (mCachedDevice.getGroupId() != BluetoothCsipSetCoordinator.GROUP_ID_INVALID) { + for (CachedBluetoothDevice member : mCachedDevice.getMemberDevice()) { + cachedBluetoothDevices.add(member); + } + } + return cachedBluetoothDevices; + } + + /** + * When user disable the Le Audio profile, the system needs to do two things. + * 1) Disable the Le Audio profile for each of the Le Audio devices. + * 2) Enable the A2dp profile and Hfp profile for the associated device. The system can't + * enable the A2dp profile and Hfp profile if the Le Audio profile is enabled. + * + * @param profile the LeAudio profile + */ + private void disableLeAudioProfile(LocalBluetoothProfile profile) { + if (profile == null || mProfileDeviceMap.get(profile.toString()) == null) { + Log.e(TAG, "There is no the LE profile or no device in mProfileDeviceMap. Do nothing."); + return; + } + for (CachedBluetoothDevice leAudioDevice : mProfileDeviceMap.get(profile.toString())) { + profile.setEnabled(leAudioDevice.getDevice(), false); + } + + LocalBluetoothProfile a2dp = mProfileManager.getA2dpProfile(); + LocalBluetoothProfile hfp = mProfileManager.getHfpClientProfile(); + if (a2dp != null && mProfileDeviceMap.get(a2dp.toString()) != null) { + for (CachedBluetoothDevice a2dpDevice : mProfileDeviceMap.get(a2dp.toString())) { + if (!a2dp.isEnabled(a2dpDevice.getDevice())) { + a2dp.setEnabled(a2dpDevice.getDevice(), true); + } + } + } + if (hfp != null && mProfileDeviceMap.get(hfp.toString()) != null) { + for (CachedBluetoothDevice hfpDevice : mProfileDeviceMap.get(hfp.toString())) { + if (!hfp.isEnabled(hfpDevice.getDevice())) { + hfp.setEnabled(hfpDevice.getDevice(), true); + } + } + } + } + + /** + * When user enable the Le Audio profile, the system needs to do two things. + * 1) Disable the A2dp profile and Hfp profile for the associated device. The system can't + * enable the Le Audio if the A2dp profile and Hfp profile are enabled. + * 2) Enable the Le Audio profile for each of the Le Audio devices. + * + * @param profile the LeAudio profile + */ + private void enableLeAudioProfile(LocalBluetoothProfile profile) { + if (profile == null || mProfileDeviceMap.get(profile.toString()) == null) { + Log.e(TAG, "There is no the LE profile or no device in mProfileDeviceMap. Do nothing."); + return; + } + LocalBluetoothProfile a2dp = mProfileManager.getA2dpProfile(); + LocalBluetoothProfile hfp = mProfileManager.getHfpClientProfile(); + if (a2dp != null && mProfileDeviceMap.get(a2dp.toString()) != null) { + for (CachedBluetoothDevice a2dpDevice : mProfileDeviceMap.get(a2dp.toString())) { + if (a2dp.isEnabled(a2dpDevice.getDevice())) { + a2dp.setEnabled(a2dpDevice.getDevice(), false); + } + } + } + if (hfp != null && mProfileDeviceMap.get(hfp.toString()) != null) { + for (CachedBluetoothDevice hfpDevice : mProfileDeviceMap.get(hfp.toString())) { + if (hfp.isEnabled(hfpDevice.getDevice())) { + hfp.setEnabled(hfpDevice.getDevice(), false); + } + } + } + for (CachedBluetoothDevice leAudioDevice : mProfileDeviceMap.get(profile.toString())) { + profile.setEnabled(leAudioDevice.getDevice(), true); + } + } + /** * This is a helper method to be called after adding a Preference for a profile. If that * profile happened to be A2dp and the device supports high quality audio, it will add a @@ -243,16 +425,33 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll @Override public void onPause() { - super.onPause(); + for (CachedBluetoothDevice item : mAllOfCachedDevices) { + item.unregisterCallback(this); + } mProfileManager.removeServiceListener(this); } @Override public void onResume() { - super.onResume(); + for (CachedBluetoothDevice item : mAllOfCachedDevices) { + item.registerCallback(this); + } mProfileManager.addServiceListener(this); } + @Override + public void onDeviceAttributesChanged() { + for (CachedBluetoothDevice item : mAllOfCachedDevices) { + item.unregisterCallback(this); + } + mAllOfCachedDevices = getAllOfCachedBluetoothDevices(); + for (CachedBluetoothDevice item : mAllOfCachedDevices) { + item.registerCallback(this); + } + + super.onDeviceAttributesChanged(); + } + @Override public void onServiceConnected() { refresh();