Merge "[Audiosharing] Set temp bond metadata for just bonded lea buds in sharing" into main
This commit is contained in:
@@ -46,6 +46,7 @@ import com.android.settings.overlay.FeatureFactory;
|
|||||||
import com.android.settingslib.bluetooth.BluetoothUtils;
|
import com.android.settingslib.bluetooth.BluetoothUtils;
|
||||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||||
import com.android.settingslib.bluetooth.HearingAidStatsLogUtils;
|
import com.android.settingslib.bluetooth.HearingAidStatsLogUtils;
|
||||||
|
import com.android.settingslib.flags.Flags;
|
||||||
import com.android.settingslib.utils.ThreadUtils;
|
import com.android.settingslib.utils.ThreadUtils;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
@@ -62,6 +63,7 @@ import java.util.concurrent.TimeUnit;
|
|||||||
public abstract class BluetoothDevicePairingDetailBase extends DeviceListPreferenceFragment {
|
public abstract class BluetoothDevicePairingDetailBase extends DeviceListPreferenceFragment {
|
||||||
private static final long AUTO_DISMISS_TIME_THRESHOLD_MS = TimeUnit.SECONDS.toMillis(15);
|
private static final long AUTO_DISMISS_TIME_THRESHOLD_MS = TimeUnit.SECONDS.toMillis(15);
|
||||||
private static final int AUTO_DISMISS_MESSAGE_ID = 1001;
|
private static final int AUTO_DISMISS_MESSAGE_ID = 1001;
|
||||||
|
private static final int AUTO_FINISH_MESSAGE_ID = 1002;
|
||||||
private static final ImmutableList<Integer> AUDIO_SHARING_PROFILES = ImmutableList.of(
|
private static final ImmutableList<Integer> AUDIO_SHARING_PROFILES = ImmutableList.of(
|
||||||
BluetoothProfile.LE_AUDIO,
|
BluetoothProfile.LE_AUDIO,
|
||||||
BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT, BluetoothProfile.VOLUME_CONTROL);
|
BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT, BluetoothProfile.VOLUME_CONTROL);
|
||||||
@@ -77,7 +79,7 @@ public abstract class BluetoothDevicePairingDetailBase extends DeviceListPrefere
|
|||||||
@Nullable
|
@Nullable
|
||||||
ProgressDialogFragment mProgressDialog = null;
|
ProgressDialogFragment mProgressDialog = null;
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
boolean mShouldTriggerAudioSharingShareThenPairFlow = false;
|
boolean mShouldTriggerShareThenPairFlow = false;
|
||||||
private CopyOnWriteArrayList<BluetoothDevice> mDevicesWithMetadataChangedListener =
|
private CopyOnWriteArrayList<BluetoothDevice> mDevicesWithMetadataChangedListener =
|
||||||
new CopyOnWriteArrayList<>();
|
new CopyOnWriteArrayList<>();
|
||||||
|
|
||||||
@@ -89,7 +91,8 @@ public abstract class BluetoothDevicePairingDetailBase extends DeviceListPrefere
|
|||||||
// onDeviceBondStateChanged(BOND_BONDED), BluetoothDevicePreference's summary has already
|
// onDeviceBondStateChanged(BOND_BONDED), BluetoothDevicePreference's summary has already
|
||||||
// change from "Pairing..." to empty since it listens to metadata changes happens earlier.
|
// change from "Pairing..." to empty since it listens to metadata changes happens earlier.
|
||||||
//
|
//
|
||||||
// In share then pair flow, we have to wait on this page till the device is connected.
|
// In pairing flow during audio sharing, we have to wait on this page till the device is
|
||||||
|
// connected to check the device type and handle extra logic for audio sharing.
|
||||||
// The BluetoothDevicePreference summary will be blank for seconds between "Pairing..." and
|
// The BluetoothDevicePreference summary will be blank for seconds between "Pairing..." and
|
||||||
// "Connecting..." To help users better understand the process, we listen to metadata change
|
// "Connecting..." To help users better understand the process, we listen to metadata change
|
||||||
// as well and show a progress dialog with "Connecting to ...." once BluetoothDevice.getState()
|
// as well and show a progress dialog with "Connecting to ...." once BluetoothDevice.getState()
|
||||||
@@ -100,10 +103,11 @@ public abstract class BluetoothDevicePairingDetailBase extends DeviceListPrefere
|
|||||||
public void onMetadataChanged(@NonNull BluetoothDevice device, int key,
|
public void onMetadataChanged(@NonNull BluetoothDevice device, int key,
|
||||||
@Nullable byte[] value) {
|
@Nullable byte[] value) {
|
||||||
Log.d(getLogTag(), "onMetadataChanged device = " + device + ", key = " + key);
|
Log.d(getLogTag(), "onMetadataChanged device = " + device + ", key = " + key);
|
||||||
if (mShouldTriggerAudioSharingShareThenPairFlow && mProgressDialog == null
|
if ((mShouldTriggerShareThenPairFlow || shouldSetTempBondMetadata())
|
||||||
|
&& mProgressDialog == null
|
||||||
&& device.getBondState() == BluetoothDevice.BOND_BONDED
|
&& device.getBondState() == BluetoothDevice.BOND_BONDED
|
||||||
&& mSelectedList.contains(device)) {
|
&& mSelectedList.contains(device)) {
|
||||||
triggerAudioSharingShareThenPairFlow(device);
|
handleDeviceBondedInAudioSharing(device);
|
||||||
// Once device is bonded, remove the listener
|
// Once device is bonded, remove the listener
|
||||||
removeOnMetadataChangedListener(device);
|
removeOnMetadataChangedListener(device);
|
||||||
}
|
}
|
||||||
@@ -133,7 +137,7 @@ public abstract class BluetoothDevicePairingDetailBase extends DeviceListPrefere
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
updateBluetooth();
|
updateBluetooth();
|
||||||
mShouldTriggerAudioSharingShareThenPairFlow = shouldTriggerAudioSharingShareThenPairFlow();
|
mShouldTriggerShareThenPairFlow = shouldTriggerShareThenPairFlow();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -177,11 +181,12 @@ public abstract class BluetoothDevicePairingDetailBase extends DeviceListPrefere
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState) {
|
public void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState) {
|
||||||
|
boolean shouldSetTempBond = shouldSetTempBondMetadata();
|
||||||
if (bondState == BluetoothDevice.BOND_BONDED) {
|
if (bondState == BluetoothDevice.BOND_BONDED) {
|
||||||
if (cachedDevice != null && mShouldTriggerAudioSharingShareThenPairFlow) {
|
if (cachedDevice != null && (mShouldTriggerShareThenPairFlow || shouldSetTempBond)) {
|
||||||
BluetoothDevice device = cachedDevice.getDevice();
|
BluetoothDevice device = cachedDevice.getDevice();
|
||||||
if (device != null && mSelectedList.contains(device)) {
|
if (device != null && mSelectedList.contains(device)) {
|
||||||
triggerAudioSharingShareThenPairFlow(device);
|
handleDeviceBondedInAudioSharing(device);
|
||||||
removeOnMetadataChangedListener(device);
|
removeOnMetadataChangedListener(device);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -190,7 +195,7 @@ public abstract class BluetoothDevicePairingDetailBase extends DeviceListPrefere
|
|||||||
finish();
|
finish();
|
||||||
return;
|
return;
|
||||||
} else if (bondState == BluetoothDevice.BOND_BONDING) {
|
} else if (bondState == BluetoothDevice.BOND_BONDING) {
|
||||||
if (mShouldTriggerAudioSharingShareThenPairFlow && cachedDevice != null) {
|
if ((mShouldTriggerShareThenPairFlow || shouldSetTempBond) && cachedDevice != null) {
|
||||||
BluetoothDevice device = cachedDevice.getDevice();
|
BluetoothDevice device = cachedDevice.getDevice();
|
||||||
if (device != null && mSelectedList.contains(device)) {
|
if (device != null && mSelectedList.contains(device)) {
|
||||||
addOnMetadataChangedListener(device);
|
addOnMetadataChangedListener(device);
|
||||||
@@ -203,7 +208,7 @@ public abstract class BluetoothDevicePairingDetailBase extends DeviceListPrefere
|
|||||||
pageId);
|
pageId);
|
||||||
HearingAidStatsLogUtils.setBondEntryForDevice(bondEntry, cachedDevice);
|
HearingAidStatsLogUtils.setBondEntryForDevice(bondEntry, cachedDevice);
|
||||||
} else if (bondState == BluetoothDevice.BOND_NONE) {
|
} else if (bondState == BluetoothDevice.BOND_NONE) {
|
||||||
if (mShouldTriggerAudioSharingShareThenPairFlow && cachedDevice != null) {
|
if ((mShouldTriggerShareThenPairFlow || shouldSetTempBond) && cachedDevice != null) {
|
||||||
BluetoothDevice device = cachedDevice.getDevice();
|
BluetoothDevice device = cachedDevice.getDevice();
|
||||||
if (device != null && mSelectedList.contains(device)) {
|
if (device != null && mSelectedList.contains(device)) {
|
||||||
removeOnMetadataChangedListener(device);
|
removeOnMetadataChangedListener(device);
|
||||||
@@ -233,21 +238,29 @@ public abstract class BluetoothDevicePairingDetailBase extends DeviceListPrefere
|
|||||||
final BluetoothDevice device = cachedDevice.getDevice();
|
final BluetoothDevice device = cachedDevice.getDevice();
|
||||||
if (device != null
|
if (device != null
|
||||||
&& mSelectedList.contains(device)) {
|
&& mSelectedList.contains(device)) {
|
||||||
if (BluetoothUtils.isAudioSharingUIAvailable(getContext())) {
|
var unused = ThreadUtils.postOnBackgroundThread(() -> {
|
||||||
if (mShouldTriggerAudioSharingShareThenPairFlow
|
if (BluetoothUtils.isAudioSharingUIAvailable(getContext())) {
|
||||||
&& state == BluetoothAdapter.STATE_CONNECTED
|
if ((mShouldTriggerShareThenPairFlow || shouldSetTempBondMetadata())
|
||||||
&& device.equals(mJustBonded)
|
&& state == BluetoothAdapter.STATE_CONNECTED
|
||||||
&& AUDIO_SHARING_PROFILES.contains(bluetoothProfile)
|
&& device.equals(mJustBonded)
|
||||||
&& isReadyForAudioSharing(cachedDevice, bluetoothProfile)) {
|
&& AUDIO_SHARING_PROFILES.contains(bluetoothProfile)
|
||||||
Log.d(getLogTag(),
|
&& isReadyForAudioSharing(cachedDevice, bluetoothProfile)) {
|
||||||
"onProfileConnectionStateChanged, ready for audio sharing");
|
Log.d(getLogTag(), "onProfileConnectionStateChanged, lea eligible");
|
||||||
dismissConnectingDialog();
|
dismissConnectingDialog();
|
||||||
mHandler.removeMessages(AUTO_DISMISS_MESSAGE_ID);
|
BluetoothUtils.setTemporaryBondMetadata(device);
|
||||||
finishFragmentWithResultForAudioSharing(device);
|
if (mShouldTriggerShareThenPairFlow) {
|
||||||
|
mHandler.removeMessages(AUTO_DISMISS_MESSAGE_ID);
|
||||||
|
postOnMainThread(() ->
|
||||||
|
finishFragmentWithResultForAudioSharing(device));
|
||||||
|
} else {
|
||||||
|
mHandler.removeMessages(AUTO_FINISH_MESSAGE_ID);
|
||||||
|
postOnMainThread(() -> finish());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
postOnMainThread(() -> finish());
|
||||||
}
|
}
|
||||||
} else {
|
});
|
||||||
finish();
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
onDeviceDeleted(cachedDevice);
|
onDeviceDeleted(cachedDevice);
|
||||||
}
|
}
|
||||||
@@ -314,7 +327,7 @@ public abstract class BluetoothDevicePairingDetailBase extends DeviceListPrefere
|
|||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
boolean shouldTriggerAudioSharingShareThenPairFlow() {
|
boolean shouldTriggerShareThenPairFlow() {
|
||||||
if (BluetoothUtils.isAudioSharingUIAvailable(getContext())) {
|
if (BluetoothUtils.isAudioSharingUIAvailable(getContext())) {
|
||||||
Activity activity = getActivity();
|
Activity activity = getActivity();
|
||||||
Intent intent = activity == null ? null : activity.getIntent();
|
Intent intent = activity == null ? null : activity.getIntent();
|
||||||
@@ -328,6 +341,16 @@ public abstract class BluetoothDevicePairingDetailBase extends DeviceListPrefere
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean shouldSetTempBondMetadata() {
|
||||||
|
return Flags.enableTemporaryBondDevicesUi()
|
||||||
|
&& BluetoothUtils.isAudioSharingUIAvailable(getContext())
|
||||||
|
&& BluetoothUtils.isBroadcasting(mLocalManager)
|
||||||
|
&& mLocalManager != null
|
||||||
|
&& mLocalManager.getCachedDeviceManager() != null
|
||||||
|
&& mLocalManager.getProfileManager().getLeAudioBroadcastAssistantProfile() != null
|
||||||
|
&& !Utils.shouldBlockPairingInAudioSharing(mLocalManager);
|
||||||
|
}
|
||||||
|
|
||||||
private boolean isReadyForAudioSharing(@NonNull CachedBluetoothDevice cachedDevice,
|
private boolean isReadyForAudioSharing(@NonNull CachedBluetoothDevice cachedDevice,
|
||||||
int justConnectedProfile) {
|
int justConnectedProfile) {
|
||||||
for (int profile : AUDIO_SHARING_PROFILES) {
|
for (int profile : AUDIO_SHARING_PROFILES) {
|
||||||
@@ -382,11 +405,10 @@ public abstract class BluetoothDevicePairingDetailBase extends DeviceListPrefere
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void triggerAudioSharingShareThenPairFlow(
|
private void handleDeviceBondedInAudioSharing(@Nullable BluetoothDevice device) {
|
||||||
@NonNull BluetoothDevice device) {
|
|
||||||
var unused = ThreadUtils.postOnBackgroundThread(() -> {
|
var unused = ThreadUtils.postOnBackgroundThread(() -> {
|
||||||
if (mJustBonded != null) {
|
if (mJustBonded != null) {
|
||||||
Log.d(getLogTag(), "Skip triggerAudioSharingShareThenPairFlow, already done");
|
Log.d(getLogTag(), "Skip handleDeviceBondedInAudioSharing, already done");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mJustBonded = device;
|
mJustBonded = device;
|
||||||
@@ -395,17 +417,38 @@ public abstract class BluetoothDevicePairingDetailBase extends DeviceListPrefere
|
|||||||
String deviceName = TextUtils.isEmpty(aliasName) ? device.getAddress()
|
String deviceName = TextUtils.isEmpty(aliasName) ? device.getAddress()
|
||||||
: aliasName;
|
: aliasName;
|
||||||
showConnectingDialog(deviceName);
|
showConnectingDialog(deviceName);
|
||||||
// Wait for AUTO_DISMISS_TIME_THRESHOLD_MS and check if the paired device supports audio
|
if (mShouldTriggerShareThenPairFlow) {
|
||||||
// sharing.
|
// For share then pair flow, we have strong signal that users wish to pair new
|
||||||
if (!mHandler.hasMessages(AUTO_DISMISS_MESSAGE_ID)) {
|
// device to join sharing.
|
||||||
mHandler.postDelayed(() ->
|
// So we wait for AUTO_DISMISS_TIME_THRESHOLD_MS, if we find that the bonded device
|
||||||
postOnMainThread(
|
// is lea in onProfileConnectionStateChanged, we finish the activity, set the device
|
||||||
() -> {
|
// as temp bond and auto add source; otherwise, show dialog to notify that the
|
||||||
Log.d(getLogTag(), "Show incompatible dialog when timeout");
|
// device is incompatible for audio sharing.
|
||||||
dismissConnectingDialog();
|
if (!mHandler.hasMessages(AUTO_DISMISS_MESSAGE_ID)) {
|
||||||
AudioSharingIncompatibleDialogFragment.show(this, deviceName,
|
mHandler.postDelayed(() ->
|
||||||
() -> finish());
|
postOnMainThread(
|
||||||
}), AUTO_DISMISS_MESSAGE_ID, AUTO_DISMISS_TIME_THRESHOLD_MS);
|
() -> {
|
||||||
|
Log.d(getLogTag(),
|
||||||
|
"Show incompatible dialog when timeout");
|
||||||
|
dismissConnectingDialog();
|
||||||
|
AudioSharingIncompatibleDialogFragment.show(this,
|
||||||
|
deviceName,
|
||||||
|
() -> finish());
|
||||||
|
}), AUTO_DISMISS_MESSAGE_ID, AUTO_DISMISS_TIME_THRESHOLD_MS);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// For other pairing request during audio sharing with sinks < 2, we wait for
|
||||||
|
// AUTO_DISMISS_TIME_THRESHOLD_MS, if we find that the bonded device is lea in
|
||||||
|
// onProfileConnectionStateChanged, we finish the activity and set the device as
|
||||||
|
// temp bond; otherwise, we just finish the activity.
|
||||||
|
if (!mHandler.hasMessages(AUTO_FINISH_MESSAGE_ID)) {
|
||||||
|
mHandler.postDelayed(() ->
|
||||||
|
postOnMainThread(
|
||||||
|
() -> {
|
||||||
|
Log.d(getLogTag(), "Finish activity when timeout");
|
||||||
|
finish();
|
||||||
|
}), AUTO_FINISH_MESSAGE_ID, AUTO_DISMISS_TIME_THRESHOLD_MS);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@@ -33,6 +33,7 @@ import android.provider.Settings;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
|
|
||||||
@@ -42,17 +43,21 @@ import com.android.settings.overlay.FeatureFactory;
|
|||||||
import com.android.settingslib.bluetooth.BluetoothUtils;
|
import com.android.settingslib.bluetooth.BluetoothUtils;
|
||||||
import com.android.settingslib.bluetooth.BluetoothUtils.ErrorListener;
|
import com.android.settingslib.bluetooth.BluetoothUtils.ErrorListener;
|
||||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||||
|
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
|
||||||
|
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
|
||||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||||
import com.android.settingslib.bluetooth.LocalBluetoothManager.BluetoothManagerCallback;
|
import com.android.settingslib.bluetooth.LocalBluetoothManager.BluetoothManagerCallback;
|
||||||
import com.android.settingslib.utils.ThreadUtils;
|
import com.android.settingslib.utils.ThreadUtils;
|
||||||
|
|
||||||
import com.google.common.base.Supplier;
|
import com.google.common.base.Supplier;
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.FutureTask;
|
import java.util.concurrent.FutureTask;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utils is a helper class that contains constants for various
|
* Utils is a helper class that contains constants for various
|
||||||
@@ -293,4 +298,30 @@ public final class Utils {
|
|||||||
ThreadUtils.postOnMainThread(runnable);
|
ThreadUtils.postOnMainThread(runnable);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if need to block pairing during audio sharing
|
||||||
|
*
|
||||||
|
* @param localBtManager {@link LocalBluetoothManager}
|
||||||
|
* @return if need to block pairing during audio sharing
|
||||||
|
*/
|
||||||
|
public static boolean shouldBlockPairingInAudioSharing(
|
||||||
|
@NonNull LocalBluetoothManager localBtManager) {
|
||||||
|
if (!BluetoothUtils.isBroadcasting(localBtManager)) return false;
|
||||||
|
LocalBluetoothLeBroadcastAssistant assistant =
|
||||||
|
localBtManager.getProfileManager().getLeAudioBroadcastAssistantProfile();
|
||||||
|
CachedBluetoothDeviceManager deviceManager = localBtManager.getCachedDeviceManager();
|
||||||
|
List<BluetoothDevice> connectedDevices =
|
||||||
|
assistant == null ? ImmutableList.of() : assistant.getAllConnectedDevices();
|
||||||
|
// Block the pairing if there is ongoing audio sharing session and
|
||||||
|
// a) there is already one temp bond sink connected
|
||||||
|
// or b) there are already two sinks joining the audio sharing
|
||||||
|
return assistant != null && deviceManager != null
|
||||||
|
&& (connectedDevices.stream().anyMatch(BluetoothUtils::isTemporaryBondDevice)
|
||||||
|
|| connectedDevices.stream().filter(
|
||||||
|
d -> BluetoothUtils.hasActiveLocalBroadcastSourceForBtDevice(d,
|
||||||
|
localBtManager))
|
||||||
|
.map(d -> BluetoothUtils.getGroupId(deviceManager.findDevice(d))).collect(
|
||||||
|
Collectors.toSet()).size() >= 2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -18,6 +18,7 @@ package com.android.settings.bluetooth;
|
|||||||
|
|
||||||
import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast.EXTRA_BT_DEVICE_TO_AUTO_ADD_SOURCE;
|
import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast.EXTRA_BT_DEVICE_TO_AUTO_ADD_SOURCE;
|
||||||
import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast.EXTRA_PAIR_AND_JOIN_SHARING;
|
import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast.EXTRA_PAIR_AND_JOIN_SHARING;
|
||||||
|
import static com.android.settingslib.bluetooth.devicesettings.data.repository.DeviceSettingServiceConnection.METADATA_FAST_PAIR_CUSTOMIZED_FIELDS;
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
@@ -36,6 +37,7 @@ import static org.robolectric.Shadows.shadowOf;
|
|||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.bluetooth.BluetoothAdapter;
|
import android.bluetooth.BluetoothAdapter;
|
||||||
import android.bluetooth.BluetoothDevice;
|
import android.bluetooth.BluetoothDevice;
|
||||||
|
import android.bluetooth.BluetoothLeBroadcastReceiveState;
|
||||||
import android.bluetooth.BluetoothProfile;
|
import android.bluetooth.BluetoothProfile;
|
||||||
import android.bluetooth.BluetoothStatusCodes;
|
import android.bluetooth.BluetoothStatusCodes;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@@ -44,6 +46,8 @@ import android.content.res.Resources;
|
|||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
|
import android.platform.test.annotations.DisableFlags;
|
||||||
|
import android.platform.test.annotations.EnableFlags;
|
||||||
import android.platform.test.flag.junit.SetFlagsRule;
|
import android.platform.test.flag.junit.SetFlagsRule;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
|
|
||||||
@@ -62,9 +66,15 @@ import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
|
|||||||
import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
|
import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
|
||||||
import com.android.settings.testutils.shadow.ShadowFragment;
|
import com.android.settings.testutils.shadow.ShadowFragment;
|
||||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||||
|
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
|
||||||
|
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast;
|
||||||
|
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
|
||||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||||
|
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
|
||||||
import com.android.settingslib.flags.Flags;
|
import com.android.settingslib.flags.Flags;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -112,6 +122,14 @@ public class BluetoothDevicePairingDetailBaseTest {
|
|||||||
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
||||||
private LocalBluetoothManager mLocalManager;
|
private LocalBluetoothManager mLocalManager;
|
||||||
@Mock
|
@Mock
|
||||||
|
private CachedBluetoothDeviceManager mDeviceManager;
|
||||||
|
@Mock
|
||||||
|
private LocalBluetoothProfileManager mProfileManager;
|
||||||
|
@Mock
|
||||||
|
private LocalBluetoothLeBroadcast mBroadcast;
|
||||||
|
@Mock
|
||||||
|
private LocalBluetoothLeBroadcastAssistant mAssistant;
|
||||||
|
@Mock
|
||||||
private CachedBluetoothDevice mCachedBluetoothDevice;
|
private CachedBluetoothDevice mCachedBluetoothDevice;
|
||||||
@Mock
|
@Mock
|
||||||
private Drawable mDrawable;
|
private Drawable mDrawable;
|
||||||
@@ -197,11 +215,13 @@ public class BluetoothDevicePairingDetailBaseTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onDeviceBondStateChanged_bonded_pairAndJoinSharingDisabled_finish() {
|
@EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
|
||||||
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
@DisableFlags(Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI)
|
||||||
|
public void onDeviceBondStateChanged_bonded_notPairInSharing_finish() {
|
||||||
when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
|
when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
|
||||||
mFragment.mSelectedList.add(mBluetoothDevice);
|
mFragment.mSelectedList.add(mBluetoothDevice);
|
||||||
setUpFragmentWithPairAndJoinSharingIntent(false);
|
setUpFragmentWithShareThenPairIntent(false);
|
||||||
|
setUpAudioSharingStates(/* enabled = */ false, /* needSetTempBondMetadata = */ false);
|
||||||
mFragment.onDeviceBondStateChanged(mCachedBluetoothDevice, BluetoothDevice.BOND_BONDED);
|
mFragment.onDeviceBondStateChanged(mCachedBluetoothDevice, BluetoothDevice.BOND_BONDED);
|
||||||
|
|
||||||
verify(mFragment).finish();
|
verify(mFragment).finish();
|
||||||
@@ -209,12 +229,14 @@ public class BluetoothDevicePairingDetailBaseTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Config(shadows = ShadowDialogFragment.class)
|
@Config(shadows = ShadowDialogFragment.class)
|
||||||
public void onDeviceBondStateChanged_bonded_pairAndJoinSharingEnabled_handle() {
|
@EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
|
||||||
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
@DisableFlags(Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI)
|
||||||
|
public void onDeviceBondStateChanged_bonded_shareThenPair_handle() {
|
||||||
ShadowDialogFragment.reset();
|
ShadowDialogFragment.reset();
|
||||||
when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
|
when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
|
||||||
mFragment.mSelectedList.add(mBluetoothDevice);
|
mFragment.mSelectedList.add(mBluetoothDevice);
|
||||||
setUpFragmentWithPairAndJoinSharingIntent(true);
|
setUpFragmentWithShareThenPairIntent(true);
|
||||||
|
setUpAudioSharingStates(/* enabled = */ true, /* needSetTempBondMetadata = */ false);
|
||||||
mFragment.onDeviceBondStateChanged(mCachedBluetoothDevice, BluetoothDevice.BOND_BONDED);
|
mFragment.onDeviceBondStateChanged(mCachedBluetoothDevice, BluetoothDevice.BOND_BONDED);
|
||||||
shadowOf(Looper.getMainLooper()).idle();
|
shadowOf(Looper.getMainLooper()).idle();
|
||||||
|
|
||||||
@@ -231,11 +253,37 @@ public class BluetoothDevicePairingDetailBaseTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onDeviceBondStateChanged_bonding_pairAndJoinSharingDisabled_doNothing() {
|
@Config(shadows = ShadowDialogFragment.class)
|
||||||
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
@EnableFlags({Flags.FLAG_ENABLE_LE_AUDIO_SHARING, Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI})
|
||||||
|
public void onDeviceBondStateChanged_bonded_pairAfterShare_handle() {
|
||||||
|
ShadowDialogFragment.reset();
|
||||||
when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
|
when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
|
||||||
mFragment.mSelectedList.add(mBluetoothDevice);
|
mFragment.mSelectedList.add(mBluetoothDevice);
|
||||||
setUpFragmentWithPairAndJoinSharingIntent(false);
|
setUpFragmentWithShareThenPairIntent(false);
|
||||||
|
setUpAudioSharingStates(/* enabled = */ true, /* needSetTempBondMetadata = */ true);
|
||||||
|
mFragment.onDeviceBondStateChanged(mCachedBluetoothDevice, BluetoothDevice.BOND_BONDED);
|
||||||
|
shadowOf(Looper.getMainLooper()).idle();
|
||||||
|
|
||||||
|
ProgressDialogFragment progressDialog = mFragment.mProgressDialog;
|
||||||
|
assertThat(progressDialog).isNotNull();
|
||||||
|
assertThat(progressDialog.getMessage()).isEqualTo(
|
||||||
|
mContext.getString(R.string.progress_dialog_connect_device_content,
|
||||||
|
TEST_DEVICE_ADDRESS));
|
||||||
|
assertThat(
|
||||||
|
ShadowDialogFragment.isIsShowing(ProgressDialogFragment.class.getName())).isTrue();
|
||||||
|
verify(mFragment, never()).finish();
|
||||||
|
|
||||||
|
ShadowDialogFragment.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
|
||||||
|
@DisableFlags(Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI)
|
||||||
|
public void onDeviceBondStateChanged_bonding_notPairInSharing_doNothing() {
|
||||||
|
when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
|
||||||
|
mFragment.mSelectedList.add(mBluetoothDevice);
|
||||||
|
setUpFragmentWithShareThenPairIntent(false);
|
||||||
|
setUpAudioSharingStates(/* enabled = */ false, /* needSetTempBondMetadata = */ false);
|
||||||
mFragment.onDeviceBondStateChanged(mCachedBluetoothDevice, BluetoothDevice.BOND_BONDING);
|
mFragment.onDeviceBondStateChanged(mCachedBluetoothDevice, BluetoothDevice.BOND_BONDING);
|
||||||
|
|
||||||
verify(mBluetoothAdapter, never()).addOnMetadataChangedListener(any(BluetoothDevice.class),
|
verify(mBluetoothAdapter, never()).addOnMetadataChangedListener(any(BluetoothDevice.class),
|
||||||
@@ -243,11 +291,13 @@ public class BluetoothDevicePairingDetailBaseTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onDeviceBondStateChanged_bonding_pairAndJoinSharingEnabled_addListener() {
|
@EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
|
||||||
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
@DisableFlags(Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI)
|
||||||
|
public void onDeviceBondStateChanged_bonding_shareThenPair_addListener() {
|
||||||
when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
|
when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
|
||||||
mFragment.mSelectedList.add(mBluetoothDevice);
|
mFragment.mSelectedList.add(mBluetoothDevice);
|
||||||
setUpFragmentWithPairAndJoinSharingIntent(true);
|
setUpFragmentWithShareThenPairIntent(true);
|
||||||
|
setUpAudioSharingStates(/* enabled = */ true, /* needSetTempBondMetadata = */ false);
|
||||||
mFragment.onDeviceBondStateChanged(mCachedBluetoothDevice, BluetoothDevice.BOND_BONDING);
|
mFragment.onDeviceBondStateChanged(mCachedBluetoothDevice, BluetoothDevice.BOND_BONDING);
|
||||||
|
|
||||||
verify(mBluetoothAdapter).addOnMetadataChangedListener(eq(mBluetoothDevice),
|
verify(mBluetoothAdapter).addOnMetadataChangedListener(eq(mBluetoothDevice),
|
||||||
@@ -256,8 +306,22 @@ public class BluetoothDevicePairingDetailBaseTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onDeviceBondStateChanged_unbonded_pairAndJoinSharingDisabled_doNothing() {
|
@EnableFlags({Flags.FLAG_ENABLE_LE_AUDIO_SHARING, Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI})
|
||||||
mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
public void onDeviceBondStateChanged_bonding_pairAfterShare_addListener() {
|
||||||
|
when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
|
||||||
|
mFragment.mSelectedList.add(mBluetoothDevice);
|
||||||
|
setUpFragmentWithShareThenPairIntent(false);
|
||||||
|
setUpAudioSharingStates(/* enabled = */ true, /* needSetTempBondMetadata = */ true);
|
||||||
|
mFragment.onDeviceBondStateChanged(mCachedBluetoothDevice, BluetoothDevice.BOND_BONDING);
|
||||||
|
|
||||||
|
verify(mBluetoothAdapter).addOnMetadataChangedListener(eq(mBluetoothDevice),
|
||||||
|
any(Executor.class),
|
||||||
|
any(BluetoothAdapter.OnMetadataChangedListener.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisableFlags({Flags.FLAG_ENABLE_LE_AUDIO_SHARING, Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI})
|
||||||
|
public void onDeviceBondStateChanged_unbonded_notPairInSharing_doNothing() {
|
||||||
when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
|
when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
|
||||||
mFragment.mSelectedList.add(mBluetoothDevice);
|
mFragment.mSelectedList.add(mBluetoothDevice);
|
||||||
mFragment.onDeviceBondStateChanged(mCachedBluetoothDevice, BluetoothDevice.BOND_NONE);
|
mFragment.onDeviceBondStateChanged(mCachedBluetoothDevice, BluetoothDevice.BOND_NONE);
|
||||||
@@ -267,11 +331,13 @@ public class BluetoothDevicePairingDetailBaseTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onDeviceBondStateChanged_unbonded_pairAndJoinSharingEnabled_removeListener() {
|
@EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
|
||||||
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
@DisableFlags(Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI)
|
||||||
|
public void onDeviceBondStateChanged_unbonded_shareThenPair_removeListener() {
|
||||||
when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
|
when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
|
||||||
mFragment.mSelectedList.add(mBluetoothDevice);
|
mFragment.mSelectedList.add(mBluetoothDevice);
|
||||||
setUpFragmentWithPairAndJoinSharingIntent(true);
|
setUpFragmentWithShareThenPairIntent(true);
|
||||||
|
setUpAudioSharingStates(/* enabled = */ true, /* needSetTempBondMetadata = */ false);
|
||||||
mFragment.onDeviceBondStateChanged(mCachedBluetoothDevice, BluetoothDevice.BOND_BONDING);
|
mFragment.onDeviceBondStateChanged(mCachedBluetoothDevice, BluetoothDevice.BOND_BONDING);
|
||||||
mFragment.onDeviceBondStateChanged(mCachedBluetoothDevice, BluetoothDevice.BOND_NONE);
|
mFragment.onDeviceBondStateChanged(mCachedBluetoothDevice, BluetoothDevice.BOND_NONE);
|
||||||
|
|
||||||
@@ -280,8 +346,23 @@ public class BluetoothDevicePairingDetailBaseTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onProfileConnectionStateChanged_deviceInSelectedListAndConnected_finish() {
|
@EnableFlags({Flags.FLAG_ENABLE_LE_AUDIO_SHARING, Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI})
|
||||||
mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
public void onDeviceBondStateChanged_unbonded_pairAfterShare_removeListener() {
|
||||||
|
when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
|
||||||
|
mFragment.mSelectedList.add(mBluetoothDevice);
|
||||||
|
setUpFragmentWithShareThenPairIntent(false);
|
||||||
|
setUpAudioSharingStates(/* enabled = */ true, /* needSetTempBondMetadata = */ true);
|
||||||
|
mFragment.onDeviceBondStateChanged(mCachedBluetoothDevice, BluetoothDevice.BOND_BONDING);
|
||||||
|
mFragment.onDeviceBondStateChanged(mCachedBluetoothDevice, BluetoothDevice.BOND_NONE);
|
||||||
|
|
||||||
|
verify(mBluetoothAdapter).removeOnMetadataChangedListener(eq(mBluetoothDevice),
|
||||||
|
any(BluetoothAdapter.OnMetadataChangedListener.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisableFlags({Flags.FLAG_ENABLE_LE_AUDIO_SHARING, Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI})
|
||||||
|
public void
|
||||||
|
onProfileConnectionStateChanged_deviceInSelectedListAndConnected_notInSharing_finish() {
|
||||||
final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_B);
|
final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_B);
|
||||||
mFragment.mSelectedList.add(mBluetoothDevice);
|
mFragment.mSelectedList.add(mBluetoothDevice);
|
||||||
mFragment.mSelectedList.add(device);
|
mFragment.mSelectedList.add(device);
|
||||||
@@ -291,19 +372,22 @@ public class BluetoothDevicePairingDetailBaseTest {
|
|||||||
|
|
||||||
mFragment.onProfileConnectionStateChanged(mCachedBluetoothDevice,
|
mFragment.onProfileConnectionStateChanged(mCachedBluetoothDevice,
|
||||||
BluetoothAdapter.STATE_CONNECTED, BluetoothProfile.A2DP);
|
BluetoothAdapter.STATE_CONNECTED, BluetoothProfile.A2DP);
|
||||||
|
shadowOf(Looper.getMainLooper()).idle();
|
||||||
|
|
||||||
verify(mFragment).finish();
|
verify(mFragment).finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Config(shadows = ShadowDialogFragment.class)
|
@Config(shadows = ShadowDialogFragment.class)
|
||||||
|
@EnableFlags({Flags.FLAG_ENABLE_LE_AUDIO_SHARING, Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI})
|
||||||
public void
|
public void
|
||||||
onProfileConnectionStateChanged_deviceInSelectedListAndConnected_pairAndJoinSharing() {
|
onProfileConnectionStateChanged_inSelectedListAndConnected_shareThenPair_handle() {
|
||||||
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
|
||||||
ShadowDialogFragment.reset();
|
ShadowDialogFragment.reset();
|
||||||
when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
|
BluetoothDevice device = spy(mBluetoothDevice);
|
||||||
mFragment.mSelectedList.add(mBluetoothDevice);
|
when(mCachedBluetoothDevice.getDevice()).thenReturn(device);
|
||||||
setUpFragmentWithPairAndJoinSharingIntent(true);
|
mFragment.mSelectedList.add(device);
|
||||||
|
setUpFragmentWithShareThenPairIntent(true);
|
||||||
|
setUpAudioSharingStates(/* enabled = */ true, /* needSetTempBondMetadata = */ false);
|
||||||
mFragment.onDeviceBondStateChanged(mCachedBluetoothDevice, BluetoothDevice.BOND_BONDED);
|
mFragment.onDeviceBondStateChanged(mCachedBluetoothDevice, BluetoothDevice.BOND_BONDED);
|
||||||
shadowOf(Looper.getMainLooper()).idle();
|
shadowOf(Looper.getMainLooper()).idle();
|
||||||
|
|
||||||
@@ -316,6 +400,7 @@ public class BluetoothDevicePairingDetailBaseTest {
|
|||||||
BluetoothAdapter.STATE_CONNECTED, BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT);
|
BluetoothAdapter.STATE_CONNECTED, BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT);
|
||||||
shadowOf(Looper.getMainLooper()).idle();
|
shadowOf(Looper.getMainLooper()).idle();
|
||||||
|
|
||||||
|
verify(device).setMetadata(eq(METADATA_FAST_PAIR_CUSTOMIZED_FIELDS), any());
|
||||||
ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
|
ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
|
||||||
verify(mFragment.getActivity()).setResult(eq(Activity.RESULT_OK), captor.capture());
|
verify(mFragment.getActivity()).setResult(eq(Activity.RESULT_OK), captor.capture());
|
||||||
Intent intent = captor.getValue();
|
Intent intent = captor.getValue();
|
||||||
@@ -325,15 +410,44 @@ public class BluetoothDevicePairingDetailBaseTest {
|
|||||||
BluetoothDevice.class)
|
BluetoothDevice.class)
|
||||||
: null;
|
: null;
|
||||||
assertThat(btDevice).isNotNull();
|
assertThat(btDevice).isNotNull();
|
||||||
assertThat(btDevice).isEqualTo(mBluetoothDevice);
|
assertThat(btDevice).isEqualTo(device);
|
||||||
verify(mFragment).finish();
|
verify(mFragment).finish();
|
||||||
|
|
||||||
ShadowDialogFragment.reset();
|
ShadowDialogFragment.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@Config(shadows = ShadowDialogFragment.class)
|
||||||
|
@EnableFlags({Flags.FLAG_ENABLE_LE_AUDIO_SHARING, Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI})
|
||||||
|
public void
|
||||||
|
onProfileConnectionStateChanged_inSelectedListAndConnected_pairAfterShare_handle() {
|
||||||
|
ShadowDialogFragment.reset();
|
||||||
|
BluetoothDevice device = spy(mBluetoothDevice);
|
||||||
|
when(mCachedBluetoothDevice.getDevice()).thenReturn(device);
|
||||||
|
mFragment.mSelectedList.add(device);
|
||||||
|
setUpFragmentWithShareThenPairIntent(false);
|
||||||
|
setUpAudioSharingStates(/* enabled = */ true, /* needSetTempBondMetadata = */ true);
|
||||||
|
mFragment.onDeviceBondStateChanged(mCachedBluetoothDevice, BluetoothDevice.BOND_BONDED);
|
||||||
|
shadowOf(Looper.getMainLooper()).idle();
|
||||||
|
|
||||||
|
when(mCachedBluetoothDevice.isConnected()).thenReturn(true);
|
||||||
|
when(mCachedBluetoothDevice.isConnectedLeAudioDevice()).thenReturn(true);
|
||||||
|
when(mCachedBluetoothDevice.isConnectedLeAudioBroadcastAssistantDevice()).thenReturn(true);
|
||||||
|
when(mCachedBluetoothDevice.isConnectedVolumeControlDevice()).thenReturn(true);
|
||||||
|
|
||||||
|
mFragment.onProfileConnectionStateChanged(mCachedBluetoothDevice,
|
||||||
|
BluetoothAdapter.STATE_CONNECTED, BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT);
|
||||||
|
shadowOf(Looper.getMainLooper()).idle();
|
||||||
|
|
||||||
|
verify(device).setMetadata(eq(METADATA_FAST_PAIR_CUSTOMIZED_FIELDS), any());
|
||||||
|
verify(mFragment).finish();
|
||||||
|
|
||||||
|
ShadowDialogFragment.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisableFlags({Flags.FLAG_ENABLE_LE_AUDIO_SHARING, Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI})
|
||||||
public void onProfileConnectionStateChanged_deviceNotInSelectedList_doNothing() {
|
public void onProfileConnectionStateChanged_deviceNotInSelectedList_doNothing() {
|
||||||
mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
|
||||||
final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_B);
|
final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_B);
|
||||||
mFragment.mSelectedList.add(device);
|
mFragment.mSelectedList.add(device);
|
||||||
|
|
||||||
@@ -347,8 +461,8 @@ public class BluetoothDevicePairingDetailBaseTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@DisableFlags({Flags.FLAG_ENABLE_LE_AUDIO_SHARING, Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI})
|
||||||
public void onProfileConnectionStateChanged_deviceDisconnected_doNothing() {
|
public void onProfileConnectionStateChanged_deviceDisconnected_doNothing() {
|
||||||
mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
|
||||||
final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_B);
|
final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_B);
|
||||||
mFragment.mSelectedList.add(mBluetoothDevice);
|
mFragment.mSelectedList.add(mBluetoothDevice);
|
||||||
mFragment.mSelectedList.add(device);
|
mFragment.mSelectedList.add(device);
|
||||||
@@ -363,8 +477,8 @@ public class BluetoothDevicePairingDetailBaseTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@DisableFlags({Flags.FLAG_ENABLE_LE_AUDIO_SHARING, Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI})
|
||||||
public void onProfileConnectionStateChanged_deviceInPreferenceMapAndConnected_removed() {
|
public void onProfileConnectionStateChanged_deviceInPreferenceMapAndConnected_removed() {
|
||||||
mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
|
||||||
final BluetoothDevicePreference preference =
|
final BluetoothDevicePreference preference =
|
||||||
new BluetoothDevicePreference(mContext, mCachedBluetoothDevice,
|
new BluetoothDevicePreference(mContext, mCachedBluetoothDevice,
|
||||||
true, BluetoothDevicePreference.SortType.TYPE_FIFO);
|
true, BluetoothDevicePreference.SortType.TYPE_FIFO);
|
||||||
@@ -381,8 +495,8 @@ public class BluetoothDevicePairingDetailBaseTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@DisableFlags({Flags.FLAG_ENABLE_LE_AUDIO_SHARING, Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI})
|
||||||
public void onProfileConnectionStateChanged_deviceNotInPreferenceMap_doNothing() {
|
public void onProfileConnectionStateChanged_deviceNotInPreferenceMap_doNothing() {
|
||||||
mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
|
||||||
final CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class);
|
final CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class);
|
||||||
final BluetoothDevicePreference preference =
|
final BluetoothDevicePreference preference =
|
||||||
new BluetoothDevicePreference(mContext, mCachedBluetoothDevice,
|
new BluetoothDevicePreference(mContext, mCachedBluetoothDevice,
|
||||||
@@ -404,9 +518,9 @@ public class BluetoothDevicePairingDetailBaseTest {
|
|||||||
// not crash
|
// not crash
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setUpFragmentWithPairAndJoinSharingIntent(boolean enablePairAndJoinSharing) {
|
private void setUpFragmentWithShareThenPairIntent(boolean enableShareThenPair) {
|
||||||
Bundle args = new Bundle();
|
Bundle args = new Bundle();
|
||||||
args.putBoolean(EXTRA_PAIR_AND_JOIN_SHARING, enablePairAndJoinSharing);
|
args.putBoolean(EXTRA_PAIR_AND_JOIN_SHARING, enableShareThenPair);
|
||||||
Intent intent = new Intent();
|
Intent intent = new Intent();
|
||||||
intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS, args);
|
intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS, args);
|
||||||
FragmentActivity activity = spy(Robolectric.setupActivity(FragmentActivity.class));
|
FragmentActivity activity = spy(Robolectric.setupActivity(FragmentActivity.class));
|
||||||
@@ -420,8 +534,39 @@ public class BluetoothDevicePairingDetailBaseTest {
|
|||||||
Lifecycle lifecycle = mock(Lifecycle.class);
|
Lifecycle lifecycle = mock(Lifecycle.class);
|
||||||
when(lifecycle.getCurrentState()).thenReturn(Lifecycle.State.RESUMED);
|
when(lifecycle.getCurrentState()).thenReturn(Lifecycle.State.RESUMED);
|
||||||
doReturn(lifecycle).when(mFragment).getLifecycle();
|
doReturn(lifecycle).when(mFragment).getLifecycle();
|
||||||
mFragment.mShouldTriggerAudioSharingShareThenPairFlow =
|
mFragment.mShouldTriggerShareThenPairFlow = mFragment.shouldTriggerShareThenPairFlow();
|
||||||
mFragment.shouldTriggerAudioSharingShareThenPairFlow();
|
}
|
||||||
|
|
||||||
|
private void setUpAudioSharingStates(boolean enabled, boolean needSetTempBondMetadata) {
|
||||||
|
when(mLocalManager.getProfileManager()).thenReturn(mProfileManager);
|
||||||
|
when(mProfileManager.getLeAudioBroadcastProfile()).thenReturn(mBroadcast);
|
||||||
|
when(mProfileManager.getLeAudioBroadcastAssistantProfile()).thenReturn(mAssistant);
|
||||||
|
when(mLocalManager.getCachedDeviceManager()).thenReturn(mDeviceManager);
|
||||||
|
if (!enabled) {
|
||||||
|
when(mBroadcast.isEnabled(null)).thenReturn(false);
|
||||||
|
} else {
|
||||||
|
when(mBroadcast.isEnabled(null)).thenReturn(true);
|
||||||
|
when(mBroadcast.getLatestBroadcastId()).thenReturn(1);
|
||||||
|
BluetoothDevice device1 = mock(BluetoothDevice.class);
|
||||||
|
CachedBluetoothDevice cachedDevice1 = mock(CachedBluetoothDevice.class);
|
||||||
|
when(mDeviceManager.findDevice(device1)).thenReturn(cachedDevice1);
|
||||||
|
when(cachedDevice1.getGroupId()).thenReturn(1);
|
||||||
|
when(cachedDevice1.getDevice()).thenReturn(device1);
|
||||||
|
BluetoothLeBroadcastReceiveState state = mock(BluetoothLeBroadcastReceiveState.class);
|
||||||
|
when(state.getBroadcastId()).thenReturn(1);
|
||||||
|
when(mAssistant.getAllSources(any())).thenReturn(ImmutableList.of(state));
|
||||||
|
if (needSetTempBondMetadata) {
|
||||||
|
when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of(device1));
|
||||||
|
} else {
|
||||||
|
BluetoothDevice device2 = mock(BluetoothDevice.class);
|
||||||
|
CachedBluetoothDevice cachedDevice2 = mock(CachedBluetoothDevice.class);
|
||||||
|
when(mDeviceManager.findDevice(device2)).thenReturn(cachedDevice2);
|
||||||
|
when(cachedDevice2.getGroupId()).thenReturn(2);
|
||||||
|
when(cachedDevice2.getDevice()).thenReturn(device2);
|
||||||
|
when(mAssistant.getAllConnectedDevices()).thenReturn(
|
||||||
|
ImmutableList.of(device1, device2));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class TestBluetoothDevicePairingDetailBase extends
|
private static class TestBluetoothDevicePairingDetailBase extends
|
||||||
|
@@ -15,6 +15,9 @@
|
|||||||
*/
|
*/
|
||||||
package com.android.settings.bluetooth;
|
package com.android.settings.bluetooth;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.ArgumentMatchers.anyInt;
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
import static org.mockito.ArgumentMatchers.anyString;
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
@@ -22,34 +25,72 @@ import static org.mockito.Mockito.mock;
|
|||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.bluetooth.BluetoothDevice;
|
||||||
|
import android.bluetooth.BluetoothLeBroadcastReceiveState;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
||||||
import com.android.settings.testutils.FakeFeatureFactory;
|
import com.android.settings.testutils.FakeFeatureFactory;
|
||||||
|
import com.android.settings.testutils.shadow.ShadowBluetoothUtils;
|
||||||
|
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||||
|
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
|
||||||
|
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast;
|
||||||
|
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
|
||||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||||
|
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
|
||||||
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
|
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
|
||||||
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.Answers;
|
import org.mockito.Answers;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.junit.MockitoJUnit;
|
||||||
|
import org.mockito.junit.MockitoRule;
|
||||||
import org.robolectric.RobolectricTestRunner;
|
import org.robolectric.RobolectricTestRunner;
|
||||||
|
import org.robolectric.annotation.Config;
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner.class)
|
@RunWith(RobolectricTestRunner.class)
|
||||||
|
@Config(shadows = {ShadowBluetoothUtils.class})
|
||||||
public class UtilsTest {
|
public class UtilsTest {
|
||||||
|
private static final int METADATA_FAST_PAIR_CUSTOMIZED_FIELDS = 25;
|
||||||
|
private static final String TEMP_BOND_METADATA =
|
||||||
|
"<TEMP_BOND_TYPE>le_audio_sharing</TEMP_BOND_TYPE>";
|
||||||
|
@Rule
|
||||||
|
public final MockitoRule mMockitoRule = MockitoJUnit.rule();
|
||||||
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
||||||
private Context mContext;
|
private Context mContext;
|
||||||
|
@Mock
|
||||||
|
private LocalBluetoothManager mLocalBtManager;
|
||||||
|
@Mock
|
||||||
|
private LocalBluetoothProfileManager mProfileManager;
|
||||||
|
@Mock
|
||||||
|
private LocalBluetoothLeBroadcast mBroadcast;
|
||||||
|
@Mock
|
||||||
|
private LocalBluetoothLeBroadcastAssistant mAssistant;
|
||||||
|
@Mock
|
||||||
|
private CachedBluetoothDeviceManager mDeviceManager;
|
||||||
|
|
||||||
private MetricsFeatureProvider mMetricsFeatureProvider;
|
private MetricsFeatureProvider mMetricsFeatureProvider;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
MockitoAnnotations.initMocks(this);
|
|
||||||
|
|
||||||
mMetricsFeatureProvider = FakeFeatureFactory.setupForTest().getMetricsFeatureProvider();
|
mMetricsFeatureProvider = FakeFeatureFactory.setupForTest().getMetricsFeatureProvider();
|
||||||
|
ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBtManager;
|
||||||
|
mLocalBtManager = Utils.getLocalBtManager(mContext);
|
||||||
|
when(mLocalBtManager.getProfileManager()).thenReturn(mProfileManager);
|
||||||
|
when(mLocalBtManager.getCachedDeviceManager()).thenReturn(mDeviceManager);
|
||||||
|
when(mProfileManager.getLeAudioBroadcastProfile()).thenReturn(mBroadcast);
|
||||||
|
when(mProfileManager.getLeAudioBroadcastAssistantProfile()).thenReturn(mAssistant);
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown() {
|
||||||
|
ShadowBluetoothUtils.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -60,4 +101,65 @@ public class UtilsTest {
|
|||||||
verify(mMetricsFeatureProvider).visible(eq(mContext), anyInt(),
|
verify(mMetricsFeatureProvider).visible(eq(mContext), anyInt(),
|
||||||
eq(MetricsEvent.ACTION_SETTINGS_BLUETOOTH_CONNECT_ERROR), anyInt());
|
eq(MetricsEvent.ACTION_SETTINGS_BLUETOOTH_CONNECT_ERROR), anyInt());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldBlockPairingInAudioSharing_broadcastOff_returnFalse() {
|
||||||
|
when(mBroadcast.isEnabled(null)).thenReturn(false);
|
||||||
|
assertThat(Utils.shouldBlockPairingInAudioSharing(mLocalBtManager)).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldBlockPairingInAudioSharing_singlePermanentBondSinkInSharing_returnFalse() {
|
||||||
|
when(mBroadcast.isEnabled(null)).thenReturn(true);
|
||||||
|
when(mBroadcast.getLatestBroadcastId()).thenReturn(1);
|
||||||
|
BluetoothDevice device = mock(BluetoothDevice.class);
|
||||||
|
CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class);
|
||||||
|
when(mDeviceManager.findDevice(device)).thenReturn(cachedDevice);
|
||||||
|
when(cachedDevice.getGroupId()).thenReturn(1);
|
||||||
|
when(cachedDevice.getDevice()).thenReturn(device);
|
||||||
|
when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of(device));
|
||||||
|
BluetoothLeBroadcastReceiveState state = mock(BluetoothLeBroadcastReceiveState.class);
|
||||||
|
when(state.getBroadcastId()).thenReturn(1);
|
||||||
|
when(mAssistant.getAllSources(device)).thenReturn(ImmutableList.of(state));
|
||||||
|
assertThat(Utils.shouldBlockPairingInAudioSharing(mLocalBtManager)).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldBlockPairingInAudioSharing_singleTempBondSinkInSharing_returnTrue() {
|
||||||
|
when(mBroadcast.isEnabled(null)).thenReturn(true);
|
||||||
|
when(mBroadcast.getLatestBroadcastId()).thenReturn(1);
|
||||||
|
BluetoothDevice device = mock(BluetoothDevice.class);
|
||||||
|
CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class);
|
||||||
|
when(mDeviceManager.findDevice(device)).thenReturn(cachedDevice);
|
||||||
|
when(cachedDevice.getGroupId()).thenReturn(1);
|
||||||
|
when(cachedDevice.getDevice()).thenReturn(device);
|
||||||
|
when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of(device));
|
||||||
|
BluetoothLeBroadcastReceiveState state = mock(BluetoothLeBroadcastReceiveState.class);
|
||||||
|
when(state.getBroadcastId()).thenReturn(1);
|
||||||
|
when(mAssistant.getAllSources(device)).thenReturn(ImmutableList.of(state));
|
||||||
|
when(device.getMetadata(METADATA_FAST_PAIR_CUSTOMIZED_FIELDS))
|
||||||
|
.thenReturn(TEMP_BOND_METADATA.getBytes());
|
||||||
|
assertThat(Utils.shouldBlockPairingInAudioSharing(mLocalBtManager)).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldBlockPairingInAudioSharing_twoSinksInSharing_returnTrue() {
|
||||||
|
when(mBroadcast.isEnabled(null)).thenReturn(true);
|
||||||
|
when(mBroadcast.getLatestBroadcastId()).thenReturn(1);
|
||||||
|
BluetoothDevice device1 = mock(BluetoothDevice.class);
|
||||||
|
BluetoothDevice device2 = mock(BluetoothDevice.class);
|
||||||
|
CachedBluetoothDevice cachedDevice1 = mock(CachedBluetoothDevice.class);
|
||||||
|
CachedBluetoothDevice cachedDevice2 = mock(CachedBluetoothDevice.class);
|
||||||
|
when(mDeviceManager.findDevice(device1)).thenReturn(cachedDevice1);
|
||||||
|
when(mDeviceManager.findDevice(device2)).thenReturn(cachedDevice2);
|
||||||
|
when(cachedDevice1.getGroupId()).thenReturn(1);
|
||||||
|
when(cachedDevice2.getGroupId()).thenReturn(2);
|
||||||
|
when(cachedDevice1.getDevice()).thenReturn(device1);
|
||||||
|
when(cachedDevice2.getDevice()).thenReturn(device2);
|
||||||
|
when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of(device1, device2));
|
||||||
|
BluetoothLeBroadcastReceiveState state = mock(BluetoothLeBroadcastReceiveState.class);
|
||||||
|
when(state.getBroadcastId()).thenReturn(1);
|
||||||
|
when(mAssistant.getAllSources(any())).thenReturn(ImmutableList.of(state));
|
||||||
|
assertThat(Utils.shouldBlockPairingInAudioSharing(mLocalBtManager)).isTrue();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user