Merge changes I094ba6be,Idbdd21a1,I03dfdc25,I40afabb0,I01e0ec91, ...

* changes:
  Update the LE audio device into the media device category
  Handle csip set member automatic pair in Setting
  Do not update the previously connected devices for the sub device
  Accept the pairing request automatically for the set member pairing
  Show the multiple Mac address for the coordinated set
  Add the pairing string for CSIP supported device
This commit is contained in:
Treehugger Robot
2021-11-29 02:11:27 +00:00
committed by Gerrit Code Review
13 changed files with 182 additions and 30 deletions

View File

@@ -2290,6 +2290,7 @@
android:exported="true"> android:exported="true">
<intent-filter> <intent-filter>
<action android:name="android.bluetooth.device.action.PAIRING_REQUEST" /> <action android:name="android.bluetooth.device.action.PAIRING_REQUEST" />
<action android:name="android.bluetooth.action.CSIS_SET_MEMBER_AVAILABLE"/>
</intent-filter> </intent-filter>
</receiver> </receiver>

View File

@@ -65,6 +65,18 @@
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead" android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead"
android:visibility="gone" /> android:visibility="gone" />
<TextView
android:id="@+id/pairing_group_message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/bluetooth_dialog_padding"
android:layout_marginEnd="@dimen/bluetooth_dialog_padding"
android:layout_marginBottom="@dimen/bluetooth_dialog_padding"
android:gravity="center_vertical"
android:text="@string/bluetooth_paring_group_msg"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1"
android:visibility="gone" />
<CheckBox <CheckBox
android:id="@+id/phonebook_sharing_message_confirm_pin" android:id="@+id/phonebook_sharing_message_confirm_pin"
android:layout_width="wrap_content" android:layout_width="wrap_content"

View File

@@ -1832,6 +1832,9 @@
<!-- Message for confirmation of passkey to complete pairing. [CHAR LIMIT=NONE] --> <!-- Message for confirmation of passkey to complete pairing. [CHAR LIMIT=NONE] -->
<string name="bluetooth_confirm_passkey_msg">To pair with:&lt;br>&lt;b><xliff:g id="device_name">%1$s</xliff:g>&lt;/b>&lt;br>&lt;br>Make sure it is showing this passkey:&lt;br>&lt;b><xliff:g id="passkey">%2$s</xliff:g>&lt;/b></string> <string name="bluetooth_confirm_passkey_msg">To pair with:&lt;br>&lt;b><xliff:g id="device_name">%1$s</xliff:g>&lt;/b>&lt;br>&lt;br>Make sure it is showing this passkey:&lt;br>&lt;b><xliff:g id="passkey">%2$s</xliff:g>&lt;/b></string>
<!-- Pairing dialog text to remind user the pairing including all of the devices in a coordinated set. [CHAR LIMIT=NONE] -->
<string name="bluetooth_paring_group_msg">Confirm to pair with the coordinated set</string>
<!-- Message when bluetooth incoming pairing request for (2.1 devices) dialog is showing --> <!-- Message when bluetooth incoming pairing request for (2.1 devices) dialog is showing -->
<string name="bluetooth_incoming_pairing_msg">From:&lt;br>&lt;b><xliff:g id="device_name">%1$s</xliff:g>&lt;/b>&lt;br>&lt;br>Pair with this device?</string> <string name="bluetooth_incoming_pairing_msg">From:&lt;br>&lt;b><xliff:g id="device_name">%1$s</xliff:g>&lt;/b>&lt;br>&lt;br>Pair with this device?</string>
@@ -1909,6 +1912,8 @@
<string name="device_details_title">Device details</string> <string name="device_details_title">Device details</string>
<!-- Title of the item to show device MAC address --> <!-- Title of the item to show device MAC address -->
<string name="bluetooth_device_mac_address">Device\'s Bluetooth address: <xliff:g id="address">%1$s</xliff:g></string> <string name="bluetooth_device_mac_address">Device\'s Bluetooth address: <xliff:g id="address">%1$s</xliff:g></string>
<!-- Title of the items to show multuple devices MAC address [CHAR LIMIT=NONE]-->
<string name="bluetooth_multuple_devices_mac_address">Device\'s Bluetooth address:\n<xliff:g id="address">%1$s</xliff:g></string>
<!-- Bluetooth device details. The title of a confirmation dialog for unpairing a paired device. [CHAR LIMIT=60] --> <!-- Bluetooth device details. The title of a confirmation dialog for unpairing a paired device. [CHAR LIMIT=60] -->
<string name="bluetooth_unpair_dialog_title">Forget device?</string> <string name="bluetooth_unpair_dialog_title">Forget device?</string>
<!-- Content Description for companion device app associations removal button [CHAR LIMIT=28]--> <!-- Content Description for companion device app associations removal button [CHAR LIMIT=28]-->

View File

@@ -70,9 +70,10 @@ public class AvailableMediaBluetoothDeviceUpdater extends BluetoothDeviceUpdater
if (DBG) { if (DBG) {
Log.d(TAG, "isFilterMatched() current audio profile : " + currentAudioProfile); Log.d(TAG, "isFilterMatched() current audio profile : " + currentAudioProfile);
} }
// If device is Hearing Aid, it is compatible with HFP and A2DP. // If device is Hearing Aid or LE Audio, it is compatible with HFP and A2DP.
// It would show in Available Devices group. // It would show in Available Devices group.
if (cachedDevice.isConnectedHearingAidDevice()) { if (cachedDevice.isConnectedHearingAidDevice()
|| cachedDevice.isConnectedLeAudioDevice()) {
return true; return true;
} }
// According to the current audio profile type, // According to the current audio profile type,

View File

@@ -16,6 +16,7 @@
package com.android.settings.bluetooth; package com.android.settings.bluetooth;
import android.bluetooth.BluetoothCsipSetCoordinator;
import android.content.Context; import android.content.Context;
import androidx.preference.PreferenceFragmentCompat; import androidx.preference.PreferenceFragmentCompat;
@@ -50,8 +51,17 @@ public class BluetoothDetailsMacAddressController extends BluetoothDetailsContro
@Override @Override
protected void refresh() { protected void refresh() {
mFooterPreference.setTitle(mContext.getString( if (mCachedDevice.getGroupId() != BluetoothCsipSetCoordinator.GROUP_ID_INVALID) {
StringBuilder mTitle = new StringBuilder(mContext.getString(
R.string.bluetooth_multuple_devices_mac_address, mCachedDevice.getAddress()));
for (CachedBluetoothDevice member: mCachedDevice.getMemberDevice()) {
mTitle.append("\n").append(member.getAddress());
}
mFooterPreference.setTitle(mTitle);
} else {
mFooterPreference.setTitle(mContext.getString(
R.string.bluetooth_device_mac_address, mCachedDevice.getAddress())); R.string.bluetooth_device_mac_address, mCachedDevice.getAddress()));
}
} }
@Override @Override

View File

@@ -28,6 +28,7 @@ import androidx.annotation.VisibleForTesting;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.bluetooth.BluetoothPairingDialogFragment.BluetoothPairingDialogListener; import com.android.settings.bluetooth.BluetoothPairingDialogFragment.BluetoothPairingDialogListener;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.bluetooth.LocalBluetoothProfile; import com.android.settingslib.bluetooth.LocalBluetoothProfile;
@@ -64,6 +65,7 @@ public class BluetoothPairingController implements OnCheckedChangeListener,
private String mDeviceName; private String mDeviceName;
private LocalBluetoothProfile mPbapClientProfile; private LocalBluetoothProfile mPbapClientProfile;
private boolean mPbapAllowed; private boolean mPbapAllowed;
private boolean mIsCoordinatedSetMember;
/** /**
* Creates an instance of a BluetoothPairingController. * Creates an instance of a BluetoothPairingController.
@@ -90,6 +92,10 @@ public class BluetoothPairingController implements OnCheckedChangeListener,
mDeviceName = mBluetoothManager.getCachedDeviceManager().getName(mDevice); mDeviceName = mBluetoothManager.getCachedDeviceManager().getName(mDevice);
mPbapClientProfile = mBluetoothManager.getProfileManager().getPbapClientProfile(); mPbapClientProfile = mBluetoothManager.getProfileManager().getPbapClientProfile();
mPasskeyFormatted = formatKey(mPasskey); mPasskeyFormatted = formatKey(mPasskey);
final CachedBluetoothDevice cachedDevice =
mBluetoothManager.getCachedDeviceManager().findDevice(mDevice);
mIsCoordinatedSetMember = (cachedDevice != null)
? cachedDevice.isCoordinatedSetMemberDevice() : false;
} }
@Override @Override
@@ -155,6 +161,15 @@ public class BluetoothPairingController implements OnCheckedChangeListener,
return mDeviceName; return mDeviceName;
} }
/**
* A method for querying if the bluetooth device is a LE coordinated set member device.
*
* @return - A boolean indicating if the device is a CSIP supported device.
*/
public boolean isCoordinatedSetMemberDevice() {
return mIsCoordinatedSetMember;
}
/** /**
* A method for querying if the bluetooth device has a profile already set up on this device. * A method for querying if the bluetooth device has a profile already set up on this device.
* *

View File

@@ -344,6 +344,9 @@ public class BluetoothPairingDialogFragment extends InstrumentedDialogFragment i
pairingViewContent.setVisibility(View.VISIBLE); pairingViewContent.setVisibility(View.VISIBLE);
pairingViewContent.setText(mPairingController.getPairingContent()); pairingViewContent.setText(mPairingController.getPairingContent());
} }
final TextView messagePairingSet = (TextView) view.findViewById(R.id.pairing_group_message);
messagePairingSet.setVisibility(mPairingController.isCoordinatedSetMemberDevice()
? View.VISIBLE : View.GONE);
return view; return view;
} }

View File

@@ -16,12 +16,16 @@
package com.android.settings.bluetooth; package com.android.settings.bluetooth;
import android.bluetooth.BluetoothCsipSetCoordinator;
import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.os.PowerManager; import android.os.PowerManager;
import android.os.UserHandle; import android.os.UserHandle;
import android.text.TextUtils;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
/** /**
* BluetoothPairingRequest is a receiver for any Bluetooth pairing request. It * BluetoothPairingRequest is a receiver for any Bluetooth pairing request. It
@@ -34,36 +38,55 @@ public final class BluetoothPairingRequest extends BroadcastReceiver {
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
String action = intent.getAction(); String action = intent.getAction();
if (action == null || !action.equals(BluetoothDevice.ACTION_PAIRING_REQUEST)) { if (action == null) {
return; return;
} }
PowerManager powerManager = context.getSystemService(PowerManager.class);
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
int pairingVariant = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, final LocalBluetoothManager mBluetoothManager = Utils.getLocalBtManager(context);
BluetoothDevice.ERROR); if (TextUtils.equals(action, BluetoothDevice.ACTION_PAIRING_REQUEST)) {
String deviceAddress = device != null ? device.getAddress() : null; PowerManager powerManager = context.getSystemService(PowerManager.class);
String deviceName = device != null ? device.getName() : null; int pairingVariant = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT,
boolean shouldShowDialog = LocalBluetoothPreferences.shouldShowDialogInForeground( BluetoothDevice.ERROR);
context, deviceAddress, deviceName); String deviceAddress = device != null ? device.getAddress() : null;
String deviceName = device != null ? device.getName() : null;
boolean shouldShowDialog = LocalBluetoothPreferences.shouldShowDialogInForeground(
context, deviceAddress, deviceName);
// Skips consent pairing dialog if the device was recently associated with CDM // Skips consent pairing dialog if the device was recently associated with CDM
if (pairingVariant == BluetoothDevice.PAIRING_VARIANT_CONSENT if (pairingVariant == BluetoothDevice.PAIRING_VARIANT_CONSENT
&& device.canBondWithoutDialog()) { && (device.canBondWithoutDialog()
device.setPairingConfirmation(true); || mBluetoothManager.getCachedDeviceManager().isOngoingPairByCsip(device))) {
} else if (powerManager.isInteractive() && shouldShowDialog) { device.setPairingConfirmation(true);
// Since the screen is on and the BT-related activity is in the foreground, } else if (powerManager.isInteractive() && shouldShowDialog) {
// just open the dialog // Since the screen is on and the BT-related activity is in the foreground,
// convert broadcast intent into activity intent (same action string) // just open the dialog
Intent pairingIntent = BluetoothPairingService.getPairingDialogIntent(context, intent, // convert broadcast intent into activity intent (same action string)
BluetoothDevice.EXTRA_PAIRING_INITIATOR_FOREGROUND); Intent pairingIntent = BluetoothPairingService.getPairingDialogIntent(context,
intent, BluetoothDevice.EXTRA_PAIRING_INITIATOR_FOREGROUND);
context.startActivityAsUser(pairingIntent, UserHandle.CURRENT); context.startActivityAsUser(pairingIntent, UserHandle.CURRENT);
} else { } else {
// Put up a notification that leads to the dialog // Put up a notification that leads to the dialog
intent.setClass(context, BluetoothPairingService.class); intent.setClass(context, BluetoothPairingService.class);
intent.setAction(BluetoothDevice.ACTION_PAIRING_REQUEST); intent.setAction(BluetoothDevice.ACTION_PAIRING_REQUEST);
context.startServiceAsUser(intent, UserHandle.CURRENT); context.startServiceAsUser(intent, UserHandle.CURRENT);
}
} else if (TextUtils.equals(action,
BluetoothCsipSetCoordinator.ACTION_CSIS_SET_MEMBER_AVAILABLE)) {
if (device == null) {
return;
}
final int groupId = intent.getIntExtra(BluetoothCsipSetCoordinator.EXTRA_CSIS_GROUP_ID,
BluetoothCsipSetCoordinator.GROUP_ID_INVALID);
if (groupId == BluetoothCsipSetCoordinator.GROUP_ID_INVALID) {
return;
}
if (mBluetoothManager.getCachedDeviceManager().shouldPairByCsip(device, groupId)) {
device.createBond(BluetoothDevice.TRANSPORT_LE);
}
} }
} }
} }

View File

@@ -70,9 +70,10 @@ public class ConnectedBluetoothDeviceUpdater extends BluetoothDeviceUpdater {
if (DBG) { if (DBG) {
Log.d(TAG, "isFilterMatched() current audio profile : " + currentAudioProfile); Log.d(TAG, "isFilterMatched() current audio profile : " + currentAudioProfile);
} }
// If device is Hearing Aid, it is compatible with HFP and A2DP. // If device is Hearing Aid or LE Audio, it is compatible with HFP and A2DP.
// It would not show in Connected Devices group. // It would not show in Connected Devices group.
if (cachedDevice.isConnectedHearingAidDevice()) { if (cachedDevice.isConnectedHearingAidDevice()
|| cachedDevice.isConnectedLeAudioDevice()) {
return false; return false;
} }
// According to the current audio profile type, // According to the current audio profile type,

View File

@@ -65,7 +65,7 @@ public class SavedBluetoothDeviceUpdater extends BluetoothDeviceUpdater
removePreferenceIfNecessary(bluetoothDevices, cachedManager); removePreferenceIfNecessary(bluetoothDevices, cachedManager);
for (BluetoothDevice device : bluetoothDevices) { for (BluetoothDevice device : bluetoothDevices) {
final CachedBluetoothDevice cachedDevice = cachedManager.findDevice(device); final CachedBluetoothDevice cachedDevice = cachedManager.findDevice(device);
if (cachedDevice != null) { if (cachedDevice != null && !cachedManager.isSubDevice(device)) {
update(cachedDevice); update(cachedDevice);
} }
} }

View File

@@ -234,6 +234,32 @@ public class AvailableMediaBluetoothDeviceUpdaterTest {
verify(mBluetoothDeviceUpdater).addPreference(mCachedBluetoothDevice); verify(mBluetoothDeviceUpdater).addPreference(mCachedBluetoothDevice);
} }
@Test
public void onProfileConnectionStateChanged_leAudioDeviceConnected_notInCall_addPreference() {
mAudioManager.setMode(AudioManager.MODE_NORMAL);
when(mBluetoothDeviceUpdater
.isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true);
when(mCachedBluetoothDevice.isConnectedLeAudioDevice()).thenReturn(true);
mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice,
BluetoothProfile.STATE_CONNECTED, BluetoothProfile.LE_AUDIO);
verify(mBluetoothDeviceUpdater).addPreference(mCachedBluetoothDevice);
}
@Test
public void onProfileConnectionStateChanged_leAudioDeviceConnected_inCall_addPreference() {
mAudioManager.setMode(AudioManager.MODE_IN_CALL);
when(mBluetoothDeviceUpdater
.isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true);
when(mCachedBluetoothDevice.isConnectedLeAudioDevice()).thenReturn(true);
mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice,
BluetoothProfile.STATE_CONNECTED, BluetoothProfile.LE_AUDIO);
verify(mBluetoothDeviceUpdater).addPreference(mCachedBluetoothDevice);
}
@Test @Test
public void onProfileConnectionStateChanged_deviceDisconnected_removePreference() { public void onProfileConnectionStateChanged_deviceDisconnected_removePreference() {
mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice, mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice,

View File

@@ -427,6 +427,34 @@ public class BluetoothPairingDialogTest {
userEntryDialogExistingTextTest("test"); userEntryDialogExistingTextTest("test");
} }
@Test
public void groupPairing_setMemberDevice_showsMessageHint() {
// set the correct dialog type
when(controller.getDialogType()).thenReturn(BluetoothPairingController.CONFIRMATION_DIALOG);
when(controller.isCoordinatedSetMemberDevice()).thenReturn(true);
// build the fragment
BluetoothPairingDialogFragment frag = makeFragment();
// verify message is what we expect it to be and is visible
TextView message = frag.getmDialog().findViewById(R.id.pairing_group_message);
assertThat(message.getVisibility()).isEqualTo(View.VISIBLE);
}
@Test
public void groupPairing_nonSetMemberDevice_hidesMessageHint() {
// set the correct dialog type
when(controller.getDialogType()).thenReturn(BluetoothPairingController.CONFIRMATION_DIALOG);
when(controller.isCoordinatedSetMemberDevice()).thenReturn(false);
// build the fragment
BluetoothPairingDialogFragment frag = makeFragment();
// verify message is what we expect it to be and is visible
TextView message = frag.getmDialog().findViewById(R.id.pairing_group_message);
assertThat(message.getVisibility()).isEqualTo(View.GONE);
}
// Runs a test simulating the user entry dialog type in a situation like device rotation, where // Runs a test simulating the user entry dialog type in a situation like device rotation, where
// the dialog fragment gets created and we already have some existing text entered into the // the dialog fragment gets created and we already have some existing text entered into the
// pin field. // pin field.

View File

@@ -234,6 +234,33 @@ public class ConnectedBluetoothDeviceUpdaterTest {
verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice); verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice);
} }
@Test
public void onProfileConnectionStateChanged_leAudioDeviceConnected_inCall_removePreference() {
mAudioManager.setMode(AudioManager.MODE_IN_CALL);
when(mBluetoothDeviceUpdater
.isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true);
when(mCachedBluetoothDevice.isConnectedLeAudioDevice()).thenReturn(true);
mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice,
BluetoothProfile.STATE_CONNECTED, BluetoothProfile.LE_AUDIO);
verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice);
}
@Test
public void onProfileConnectionStateChanged_leAudioDeviceConnected_notInCall_removePreference()
{
mAudioManager.setMode(AudioManager.MODE_NORMAL);
when(mBluetoothDeviceUpdater
.isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true);
when(mCachedBluetoothDevice.isConnectedLeAudioDevice()).thenReturn(true);
mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice,
BluetoothProfile.STATE_CONNECTED, BluetoothProfile.LE_AUDIO);
verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice);
}
@Test @Test
public void onProfileConnectionStateChanged_deviceDisconnected_removePreference() { public void onProfileConnectionStateChanged_deviceDisconnected_removePreference() {
mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice, mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice,