Merge "Support Bluetooth activation in BluetoothDevicesSlice"
This commit is contained in:
@@ -46,6 +46,7 @@ import com.android.settings.connecteddevice.ConnectedDeviceDashboardFragment;
|
|||||||
import com.android.settings.core.SubSettingLauncher;
|
import com.android.settings.core.SubSettingLauncher;
|
||||||
import com.android.settings.slices.CustomSliceRegistry;
|
import com.android.settings.slices.CustomSliceRegistry;
|
||||||
import com.android.settings.slices.CustomSliceable;
|
import com.android.settings.slices.CustomSliceable;
|
||||||
|
import com.android.settings.slices.SliceBroadcastReceiver;
|
||||||
import com.android.settings.slices.SliceBuilderUtils;
|
import com.android.settings.slices.SliceBuilderUtils;
|
||||||
import com.android.settingslib.bluetooth.BluetoothUtils;
|
import com.android.settingslib.bluetooth.BluetoothUtils;
|
||||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||||
@@ -59,10 +60,12 @@ import java.util.stream.Collectors;
|
|||||||
|
|
||||||
public class BluetoothDevicesSlice implements CustomSliceable {
|
public class BluetoothDevicesSlice implements CustomSliceable {
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
static final String BLUETOOTH_DEVICE_HASH_CODE = "bluetooth_device_hash_code";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO(b/114807655): Contextual Home Page - Connected Device
|
* Refer {@link com.android.settings.bluetooth.BluetoothDevicePreference#compareTo} to sort the
|
||||||
* Re-design sorting for new rule:
|
* Bluetooth devices by {@link CachedBluetoothDevice}.
|
||||||
* Sorting rule: Audio Streaming > Last connected > Recently connected.
|
|
||||||
*/
|
*/
|
||||||
private static final Comparator<CachedBluetoothDevice> COMPARATOR
|
private static final Comparator<CachedBluetoothDevice> COMPARATOR
|
||||||
= Comparator.naturalOrder();
|
= Comparator.naturalOrder();
|
||||||
@@ -109,12 +112,11 @@ public class BluetoothDevicesSlice implements CustomSliceable {
|
|||||||
final SliceAction primarySliceAction = SliceAction.createDeeplink(primaryActionIntent, icon,
|
final SliceAction primarySliceAction = SliceAction.createDeeplink(primaryActionIntent, icon,
|
||||||
ListBuilder.ICON_IMAGE, title);
|
ListBuilder.ICON_IMAGE, title);
|
||||||
final ListBuilder listBuilder =
|
final ListBuilder listBuilder =
|
||||||
new ListBuilder(mContext, CustomSliceRegistry.BLUETOOTH_DEVICES_SLICE_URI,
|
new ListBuilder(mContext, getUri(), ListBuilder.INFINITY)
|
||||||
ListBuilder.INFINITY)
|
|
||||||
.setAccentColor(Utils.getColorAccentDefaultColor(mContext));
|
.setAccentColor(Utils.getColorAccentDefaultColor(mContext));
|
||||||
|
|
||||||
// Get row builders by Bluetooth devices.
|
// Get row builders by Bluetooth devices.
|
||||||
final List<ListBuilder.RowBuilder> rows = getBluetoothRowBuilder(primarySliceAction);
|
final List<ListBuilder.RowBuilder> rows = getBluetoothRowBuilder();
|
||||||
|
|
||||||
// Return a header with IsError flag, if no Bluetooth devices.
|
// Return a header with IsError flag, if no Bluetooth devices.
|
||||||
if (rows.isEmpty()) {
|
if (rows.isEmpty()) {
|
||||||
@@ -131,7 +133,7 @@ public class BluetoothDevicesSlice implements CustomSliceable {
|
|||||||
.setSubtitle(getSubTitle(rows.size()))
|
.setSubtitle(getSubTitle(rows.size()))
|
||||||
.setPrimaryAction(primarySliceAction));
|
.setPrimaryAction(primarySliceAction));
|
||||||
|
|
||||||
// Add bluetooth device rows.
|
// Add Bluetooth device rows.
|
||||||
for (ListBuilder.RowBuilder rowBuilder : rows) {
|
for (ListBuilder.RowBuilder rowBuilder : rows) {
|
||||||
listBuilder.addRow(rowBuilder);
|
listBuilder.addRow(rowBuilder);
|
||||||
}
|
}
|
||||||
@@ -154,11 +156,19 @@ public class BluetoothDevicesSlice implements CustomSliceable {
|
|||||||
screenTitle,
|
screenTitle,
|
||||||
MetricsProto.MetricsEvent.SLICE)
|
MetricsProto.MetricsEvent.SLICE)
|
||||||
.setClassName(mContext.getPackageName(), SubSettings.class.getName())
|
.setClassName(mContext.getPackageName(), SubSettings.class.getName())
|
||||||
.setData(CustomSliceRegistry.BLUETOOTH_DEVICES_SLICE_URI);
|
.setData(getUri());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onNotifyChange(Intent intent) {
|
public void onNotifyChange(Intent intent) {
|
||||||
|
// Activate available media device.
|
||||||
|
final int bluetoothDeviceHashCode = intent.getIntExtra(BLUETOOTH_DEVICE_HASH_CODE, -1);
|
||||||
|
for (CachedBluetoothDevice cachedBluetoothDevice : getConnectedBluetoothDevices()) {
|
||||||
|
if (cachedBluetoothDevice.hashCode() == bluetoothDeviceHashCode) {
|
||||||
|
cachedBluetoothDevice.setActive();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -167,10 +177,10 @@ public class BluetoothDevicesSlice implements CustomSliceable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
List<CachedBluetoothDevice> getBluetoothDevices() {
|
List<CachedBluetoothDevice> getConnectedBluetoothDevices() {
|
||||||
final List<CachedBluetoothDevice> bluetoothDeviceList = new ArrayList<>();
|
final List<CachedBluetoothDevice> bluetoothDeviceList = new ArrayList<>();
|
||||||
|
|
||||||
// If Bluetooth is disable, skip to get the bluetooth devices.
|
// If Bluetooth is disable, skip to get the Bluetooth devices.
|
||||||
if (!BluetoothAdapter.getDefaultAdapter().isEnabled()) {
|
if (!BluetoothAdapter.getDefaultAdapter().isEnabled()) {
|
||||||
Log.i(TAG, "Cannot get Bluetooth devices, Bluetooth is disabled.");
|
Log.i(TAG, "Cannot get Bluetooth devices, Bluetooth is disabled.");
|
||||||
return bluetoothDeviceList;
|
return bluetoothDeviceList;
|
||||||
@@ -188,12 +198,13 @@ public class BluetoothDevicesSlice implements CustomSliceable {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO(b/114807655): Contextual Home Page - Connected Device
|
* TODO(b/114807655): Contextual Home Page - Connected Device
|
||||||
* Re-design to get all Bluetooth devices and sort them by new rule:
|
* It's under discussion for including available media devices and currently connected
|
||||||
* Sorting rule: Audio Streaming > Last connected > Recently connected.
|
* devices from Bluetooth. Will update the devices list or remove TODO later.
|
||||||
*/
|
*/
|
||||||
// Get connected Bluetooth devices and sort them.
|
// Get available media device list and sort them.
|
||||||
return cachedDevices.stream().filter(device -> device.isConnected()).sorted(
|
return cachedDevices.stream()
|
||||||
COMPARATOR).collect(Collectors.toList());
|
.filter(device -> device.isConnected() && device.isConnectedA2dpDevice())
|
||||||
|
.sorted(COMPARATOR).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
@@ -226,27 +237,35 @@ public class BluetoothDevicesSlice implements CustomSliceable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<ListBuilder.RowBuilder> getBluetoothRowBuilder(SliceAction primarySliceAction) {
|
private List<ListBuilder.RowBuilder> getBluetoothRowBuilder() {
|
||||||
|
// According Bluetooth devices to create row builders.
|
||||||
final List<ListBuilder.RowBuilder> bluetoothRows = new ArrayList<>();
|
final List<ListBuilder.RowBuilder> bluetoothRows = new ArrayList<>();
|
||||||
|
final List<CachedBluetoothDevice> bluetoothDevices = getConnectedBluetoothDevices();
|
||||||
/**
|
|
||||||
* TODO(b/114807655): Contextual Home Page - Connected Device
|
|
||||||
* Re-design to do action "activating" in primary action.
|
|
||||||
*/
|
|
||||||
// According Bluetooth device to create row builders.
|
|
||||||
final List<CachedBluetoothDevice> bluetoothDevices = getBluetoothDevices();
|
|
||||||
for (CachedBluetoothDevice bluetoothDevice : bluetoothDevices) {
|
for (CachedBluetoothDevice bluetoothDevice : bluetoothDevices) {
|
||||||
bluetoothRows.add(new ListBuilder.RowBuilder()
|
bluetoothRows.add(new ListBuilder.RowBuilder()
|
||||||
.setTitleItem(getBluetoothDeviceIcon(bluetoothDevice), ListBuilder.ICON_IMAGE)
|
.setTitleItem(getBluetoothDeviceIcon(bluetoothDevice), ListBuilder.ICON_IMAGE)
|
||||||
.setTitle(bluetoothDevice.getName())
|
.setTitle(bluetoothDevice.getName())
|
||||||
.setSubtitle(bluetoothDevice.getConnectionSummary())
|
.setSubtitle(bluetoothDevice.getConnectionSummary())
|
||||||
.setPrimaryAction(primarySliceAction)
|
.setPrimaryAction(buildBluetoothDeviceAction(bluetoothDevice))
|
||||||
.addEndItem(buildBluetoothDetailDeepLinkAction(bluetoothDevice)));
|
.addEndItem(buildBluetoothDetailDeepLinkAction(bluetoothDevice)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return bluetoothRows;
|
return bluetoothRows;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private SliceAction buildBluetoothDeviceAction(CachedBluetoothDevice bluetoothDevice) {
|
||||||
|
// Send broadcast to activate available media device.
|
||||||
|
final Intent intent = new Intent(getUri().toString())
|
||||||
|
.setClass(mContext, SliceBroadcastReceiver.class)
|
||||||
|
.putExtra(BLUETOOTH_DEVICE_HASH_CODE, bluetoothDevice.hashCode());
|
||||||
|
|
||||||
|
return SliceAction.create(
|
||||||
|
PendingIntent.getBroadcast(mContext, bluetoothDevice.hashCode(), intent, 0),
|
||||||
|
getBluetoothDeviceIcon(bluetoothDevice),
|
||||||
|
ListBuilder.ICON_IMAGE,
|
||||||
|
bluetoothDevice.getName());
|
||||||
|
}
|
||||||
|
|
||||||
private SliceAction buildBluetoothDetailDeepLinkAction(CachedBluetoothDevice bluetoothDevice) {
|
private SliceAction buildBluetoothDetailDeepLinkAction(CachedBluetoothDevice bluetoothDevice) {
|
||||||
return SliceAction.createDeeplink(
|
return SliceAction.createDeeplink(
|
||||||
getBluetoothDetailIntent(bluetoothDevice),
|
getBluetoothDetailIntent(bluetoothDevice),
|
||||||
|
@@ -21,6 +21,7 @@ import static com.google.common.truth.Truth.assertThat;
|
|||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.Mockito.doReturn;
|
import static org.mockito.Mockito.doReturn;
|
||||||
import static org.mockito.Mockito.spy;
|
import static org.mockito.Mockito.spy;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
@@ -54,6 +55,7 @@ import java.util.List;
|
|||||||
@RunWith(RobolectricTestRunner.class)
|
@RunWith(RobolectricTestRunner.class)
|
||||||
public class BluetoothDevicesSliceTest {
|
public class BluetoothDevicesSliceTest {
|
||||||
|
|
||||||
|
private static final String BLUETOOTH_MOCK_ADDRESS = "00:11:00:11:00:11";
|
||||||
private static final String BLUETOOTH_MOCK_SUMMARY = "BluetoothSummary";
|
private static final String BLUETOOTH_MOCK_SUMMARY = "BluetoothSummary";
|
||||||
private static final String BLUETOOTH_MOCK_TITLE = "BluetoothTitle";
|
private static final String BLUETOOTH_MOCK_TITLE = "BluetoothTitle";
|
||||||
|
|
||||||
@@ -96,7 +98,7 @@ public class BluetoothDevicesSliceTest {
|
|||||||
@Test
|
@Test
|
||||||
public void getSlice_hasBluetoothDevices_shouldHaveBluetoothDevicesTitle() {
|
public void getSlice_hasBluetoothDevices_shouldHaveBluetoothDevicesTitle() {
|
||||||
mockBluetoothDeviceList();
|
mockBluetoothDeviceList();
|
||||||
doReturn(mBluetoothDeviceList).when(mBluetoothDevicesSlice).getBluetoothDevices();
|
doReturn(mBluetoothDeviceList).when(mBluetoothDevicesSlice).getConnectedBluetoothDevices();
|
||||||
|
|
||||||
final Slice slice = mBluetoothDevicesSlice.getSlice();
|
final Slice slice = mBluetoothDevicesSlice.getSlice();
|
||||||
|
|
||||||
@@ -107,7 +109,7 @@ public class BluetoothDevicesSliceTest {
|
|||||||
@Test
|
@Test
|
||||||
public void getSlice_hasBluetoothDevices_shouldMatchBluetoothMockTitle() {
|
public void getSlice_hasBluetoothDevices_shouldMatchBluetoothMockTitle() {
|
||||||
mockBluetoothDeviceList();
|
mockBluetoothDeviceList();
|
||||||
doReturn(mBluetoothDeviceList).when(mBluetoothDevicesSlice).getBluetoothDevices();
|
doReturn(mBluetoothDeviceList).when(mBluetoothDevicesSlice).getConnectedBluetoothDevices();
|
||||||
|
|
||||||
final Slice slice = mBluetoothDevicesSlice.getSlice();
|
final Slice slice = mBluetoothDevicesSlice.getSlice();
|
||||||
|
|
||||||
@@ -118,7 +120,7 @@ public class BluetoothDevicesSliceTest {
|
|||||||
@Test
|
@Test
|
||||||
public void getSlice_hasBluetoothDevices_shouldHavePairNewDevice() {
|
public void getSlice_hasBluetoothDevices_shouldHavePairNewDevice() {
|
||||||
mockBluetoothDeviceList();
|
mockBluetoothDeviceList();
|
||||||
doReturn(mBluetoothDeviceList).when(mBluetoothDevicesSlice).getBluetoothDevices();
|
doReturn(mBluetoothDeviceList).when(mBluetoothDevicesSlice).getConnectedBluetoothDevices();
|
||||||
|
|
||||||
final Slice slice = mBluetoothDevicesSlice.getSlice();
|
final Slice slice = mBluetoothDevicesSlice.getSlice();
|
||||||
|
|
||||||
@@ -129,7 +131,7 @@ public class BluetoothDevicesSliceTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getSlice_noBluetoothDevices_shouldHaveNoBluetoothDevicesTitle() {
|
public void getSlice_noBluetoothDevices_shouldHaveNoBluetoothDevicesTitle() {
|
||||||
doReturn(mBluetoothDeviceList).when(mBluetoothDevicesSlice).getBluetoothDevices();
|
doReturn(mBluetoothDeviceList).when(mBluetoothDevicesSlice).getConnectedBluetoothDevices();
|
||||||
|
|
||||||
final Slice slice = mBluetoothDevicesSlice.getSlice();
|
final Slice slice = mBluetoothDevicesSlice.getSlice();
|
||||||
|
|
||||||
@@ -139,7 +141,7 @@ public class BluetoothDevicesSliceTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getSlice_noBluetoothDevices_shouldNotHavePairNewDevice() {
|
public void getSlice_noBluetoothDevices_shouldNotHavePairNewDevice() {
|
||||||
doReturn(mBluetoothDeviceList).when(mBluetoothDevicesSlice).getBluetoothDevices();
|
doReturn(mBluetoothDeviceList).when(mBluetoothDevicesSlice).getConnectedBluetoothDevices();
|
||||||
|
|
||||||
final Slice slice = mBluetoothDevicesSlice.getSlice();
|
final Slice slice = mBluetoothDevicesSlice.getSlice();
|
||||||
|
|
||||||
@@ -148,9 +150,24 @@ public class BluetoothDevicesSliceTest {
|
|||||||
mContext.getString(R.string.bluetooth_pairing_pref_title))).isFalse();
|
mContext.getString(R.string.bluetooth_pairing_pref_title))).isFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onNotifyChange_mediaDevice_shouldActivateDevice() {
|
||||||
|
mockBluetoothDeviceList();
|
||||||
|
doReturn(mBluetoothDeviceList).when(mBluetoothDevicesSlice).getConnectedBluetoothDevices();
|
||||||
|
final Intent intent = new Intent().putExtra(
|
||||||
|
BluetoothDevicesSlice.BLUETOOTH_DEVICE_HASH_CODE,
|
||||||
|
mCachedBluetoothDevice.hashCode());
|
||||||
|
|
||||||
|
mBluetoothDevicesSlice.onNotifyChange(intent);
|
||||||
|
|
||||||
|
verify(mCachedBluetoothDevice).setActive();
|
||||||
|
}
|
||||||
|
|
||||||
private void mockBluetoothDeviceList() {
|
private void mockBluetoothDeviceList() {
|
||||||
doReturn(BLUETOOTH_MOCK_TITLE).when(mCachedBluetoothDevice).getName();
|
doReturn(BLUETOOTH_MOCK_TITLE).when(mCachedBluetoothDevice).getName();
|
||||||
doReturn(BLUETOOTH_MOCK_SUMMARY).when(mCachedBluetoothDevice).getConnectionSummary();
|
doReturn(BLUETOOTH_MOCK_SUMMARY).when(mCachedBluetoothDevice).getConnectionSummary();
|
||||||
|
doReturn(BLUETOOTH_MOCK_ADDRESS).when(mCachedBluetoothDevice).getAddress();
|
||||||
|
doReturn(true).when(mCachedBluetoothDevice).isConnectedA2dpDevice();
|
||||||
mBluetoothDeviceList.add(mCachedBluetoothDevice);
|
mBluetoothDeviceList.add(mCachedBluetoothDevice);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user