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:
@@ -2290,6 +2290,7 @@
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.bluetooth.device.action.PAIRING_REQUEST" />
|
||||
<action android:name="android.bluetooth.action.CSIS_SET_MEMBER_AVAILABLE"/>
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
|
@@ -65,6 +65,18 @@
|
||||
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead"
|
||||
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
|
||||
android:id="@+id/phonebook_sharing_message_confirm_pin"
|
||||
android:layout_width="wrap_content"
|
||||
|
@@ -1832,6 +1832,9 @@
|
||||
<!-- Message for confirmation of passkey to complete pairing. [CHAR LIMIT=NONE] -->
|
||||
<string name="bluetooth_confirm_passkey_msg">To pair with:<br><b><xliff:g id="device_name">%1$s</xliff:g></b><br><br>Make sure it is showing this passkey:<br><b><xliff:g id="passkey">%2$s</xliff:g></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 -->
|
||||
<string name="bluetooth_incoming_pairing_msg">From:<br><b><xliff:g id="device_name">%1$s</xliff:g></b><br><br>Pair with this device?</string>
|
||||
|
||||
@@ -1909,6 +1912,8 @@
|
||||
<string name="device_details_title">Device details</string>
|
||||
<!-- 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>
|
||||
<!-- 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] -->
|
||||
<string name="bluetooth_unpair_dialog_title">Forget device?</string>
|
||||
<!-- Content Description for companion device app associations removal button [CHAR LIMIT=28]-->
|
||||
|
@@ -70,9 +70,10 @@ public class AvailableMediaBluetoothDeviceUpdater extends BluetoothDeviceUpdater
|
||||
if (DBG) {
|
||||
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.
|
||||
if (cachedDevice.isConnectedHearingAidDevice()) {
|
||||
if (cachedDevice.isConnectedHearingAidDevice()
|
||||
|| cachedDevice.isConnectedLeAudioDevice()) {
|
||||
return true;
|
||||
}
|
||||
// According to the current audio profile type,
|
||||
|
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.settings.bluetooth;
|
||||
|
||||
import android.bluetooth.BluetoothCsipSetCoordinator;
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.preference.PreferenceFragmentCompat;
|
||||
@@ -50,8 +51,17 @@ public class BluetoothDetailsMacAddressController extends BluetoothDetailsContro
|
||||
|
||||
@Override
|
||||
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()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -28,6 +28,7 @@ import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.bluetooth.BluetoothPairingDialogFragment.BluetoothPairingDialogListener;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothProfile;
|
||||
|
||||
@@ -64,6 +65,7 @@ public class BluetoothPairingController implements OnCheckedChangeListener,
|
||||
private String mDeviceName;
|
||||
private LocalBluetoothProfile mPbapClientProfile;
|
||||
private boolean mPbapAllowed;
|
||||
private boolean mIsCoordinatedSetMember;
|
||||
|
||||
/**
|
||||
* Creates an instance of a BluetoothPairingController.
|
||||
@@ -90,6 +92,10 @@ public class BluetoothPairingController implements OnCheckedChangeListener,
|
||||
mDeviceName = mBluetoothManager.getCachedDeviceManager().getName(mDevice);
|
||||
mPbapClientProfile = mBluetoothManager.getProfileManager().getPbapClientProfile();
|
||||
mPasskeyFormatted = formatKey(mPasskey);
|
||||
final CachedBluetoothDevice cachedDevice =
|
||||
mBluetoothManager.getCachedDeviceManager().findDevice(mDevice);
|
||||
mIsCoordinatedSetMember = (cachedDevice != null)
|
||||
? cachedDevice.isCoordinatedSetMemberDevice() : false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -155,6 +161,15 @@ public class BluetoothPairingController implements OnCheckedChangeListener,
|
||||
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.
|
||||
*
|
||||
|
@@ -344,6 +344,9 @@ public class BluetoothPairingDialogFragment extends InstrumentedDialogFragment i
|
||||
pairingViewContent.setVisibility(View.VISIBLE);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@@ -16,12 +16,16 @@
|
||||
|
||||
package com.android.settings.bluetooth;
|
||||
|
||||
import android.bluetooth.BluetoothCsipSetCoordinator;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.PowerManager;
|
||||
import android.os.UserHandle;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||
|
||||
/**
|
||||
* BluetoothPairingRequest is a receiver for any Bluetooth pairing request. It
|
||||
@@ -34,36 +38,55 @@ public final class BluetoothPairingRequest extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
String action = intent.getAction();
|
||||
if (action == null || !action.equals(BluetoothDevice.ACTION_PAIRING_REQUEST)) {
|
||||
if (action == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
PowerManager powerManager = context.getSystemService(PowerManager.class);
|
||||
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
|
||||
int pairingVariant = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT,
|
||||
BluetoothDevice.ERROR);
|
||||
String deviceAddress = device != null ? device.getAddress() : null;
|
||||
String deviceName = device != null ? device.getName() : null;
|
||||
boolean shouldShowDialog = LocalBluetoothPreferences.shouldShowDialogInForeground(
|
||||
context, deviceAddress, deviceName);
|
||||
final LocalBluetoothManager mBluetoothManager = Utils.getLocalBtManager(context);
|
||||
if (TextUtils.equals(action, BluetoothDevice.ACTION_PAIRING_REQUEST)) {
|
||||
PowerManager powerManager = context.getSystemService(PowerManager.class);
|
||||
int pairingVariant = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT,
|
||||
BluetoothDevice.ERROR);
|
||||
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
|
||||
if (pairingVariant == BluetoothDevice.PAIRING_VARIANT_CONSENT
|
||||
&& device.canBondWithoutDialog()) {
|
||||
device.setPairingConfirmation(true);
|
||||
} else if (powerManager.isInteractive() && shouldShowDialog) {
|
||||
// Since the screen is on and the BT-related activity is in the foreground,
|
||||
// just open the dialog
|
||||
// convert broadcast intent into activity intent (same action string)
|
||||
Intent pairingIntent = BluetoothPairingService.getPairingDialogIntent(context, intent,
|
||||
BluetoothDevice.EXTRA_PAIRING_INITIATOR_FOREGROUND);
|
||||
// Skips consent pairing dialog if the device was recently associated with CDM
|
||||
if (pairingVariant == BluetoothDevice.PAIRING_VARIANT_CONSENT
|
||||
&& (device.canBondWithoutDialog()
|
||||
|| mBluetoothManager.getCachedDeviceManager().isOngoingPairByCsip(device))) {
|
||||
device.setPairingConfirmation(true);
|
||||
} else if (powerManager.isInteractive() && shouldShowDialog) {
|
||||
// Since the screen is on and the BT-related activity is in the foreground,
|
||||
// just open the dialog
|
||||
// convert broadcast intent into activity intent (same action string)
|
||||
Intent pairingIntent = BluetoothPairingService.getPairingDialogIntent(context,
|
||||
intent, BluetoothDevice.EXTRA_PAIRING_INITIATOR_FOREGROUND);
|
||||
|
||||
context.startActivityAsUser(pairingIntent, UserHandle.CURRENT);
|
||||
} else {
|
||||
// Put up a notification that leads to the dialog
|
||||
intent.setClass(context, BluetoothPairingService.class);
|
||||
intent.setAction(BluetoothDevice.ACTION_PAIRING_REQUEST);
|
||||
context.startServiceAsUser(intent, UserHandle.CURRENT);
|
||||
context.startActivityAsUser(pairingIntent, UserHandle.CURRENT);
|
||||
} else {
|
||||
// Put up a notification that leads to the dialog
|
||||
intent.setClass(context, BluetoothPairingService.class);
|
||||
intent.setAction(BluetoothDevice.ACTION_PAIRING_REQUEST);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -70,9 +70,10 @@ public class ConnectedBluetoothDeviceUpdater extends BluetoothDeviceUpdater {
|
||||
if (DBG) {
|
||||
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.
|
||||
if (cachedDevice.isConnectedHearingAidDevice()) {
|
||||
if (cachedDevice.isConnectedHearingAidDevice()
|
||||
|| cachedDevice.isConnectedLeAudioDevice()) {
|
||||
return false;
|
||||
}
|
||||
// According to the current audio profile type,
|
||||
|
@@ -65,7 +65,7 @@ public class SavedBluetoothDeviceUpdater extends BluetoothDeviceUpdater
|
||||
removePreferenceIfNecessary(bluetoothDevices, cachedManager);
|
||||
for (BluetoothDevice device : bluetoothDevices) {
|
||||
final CachedBluetoothDevice cachedDevice = cachedManager.findDevice(device);
|
||||
if (cachedDevice != null) {
|
||||
if (cachedDevice != null && !cachedManager.isSubDevice(device)) {
|
||||
update(cachedDevice);
|
||||
}
|
||||
}
|
||||
|
@@ -234,6 +234,32 @@ public class AvailableMediaBluetoothDeviceUpdaterTest {
|
||||
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
|
||||
public void onProfileConnectionStateChanged_deviceDisconnected_removePreference() {
|
||||
mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice,
|
||||
|
@@ -427,6 +427,34 @@ public class BluetoothPairingDialogTest {
|
||||
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
|
||||
// the dialog fragment gets created and we already have some existing text entered into the
|
||||
// pin field.
|
||||
|
@@ -234,6 +234,33 @@ public class ConnectedBluetoothDeviceUpdaterTest {
|
||||
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
|
||||
public void onProfileConnectionStateChanged_deviceDisconnected_removePreference() {
|
||||
mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice,
|
||||
|
Reference in New Issue
Block a user