Merge "Implement method for get previously connected devices"

This commit is contained in:
TreeHugger Robot
2019-03-12 02:50:03 +00:00
committed by Android (Google) Code Review
15 changed files with 456 additions and 128 deletions

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2019 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:viewportWidth="24"
android:viewportHeight="24"
android:width="24dp"
android:height="24dp"
android:tint="?android:attr/colorControlNormal">
<path
android:fillColor="#00000000"
android:pathData="M0 0h24v24H0z" />
<path
android:fillColor="#000000"
android:pathData="M17 1.01L7 1c-1.1 0-2 0.9-2 2v18c0 1.1 0.9 2 2 2h10c1.1 0 2 -0.9 2-2V3c0-1.1 -0.9-1.99-2-1.99zM17 19H7V5h10v14z" />
</vector>

View File

@@ -1153,6 +1153,6 @@
<!-- The notice header of Third-party licenses. not translatable -->
<string name="notice_header" translatable="false"></string>
<!-- Name of the phone device [CHAR LIMIT=NONE] -->
<string name="media_transfer_phone_device_name">Phone speaker</string>
<!-- Name of the this device. [CHAR LIMIT=30] -->
<string name="media_transfer_this_device_name">This device</string>
</resources>

View File

@@ -16,6 +16,7 @@
package com.android.settingslib.media;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.util.Log;
@@ -41,6 +42,11 @@ public class BluetoothMediaDevice extends MediaDevice {
return mCachedDevice.getName();
}
@Override
public String getSummary() {
return mCachedDevice.getConnectionSummary();
}
@Override
public int getIcon() {
//TODO(b/117129183): This is not final icon for bluetooth device, just for demo.
@@ -86,4 +92,10 @@ public class BluetoothMediaDevice extends MediaDevice {
}
return false;
}
@Override
public boolean isConnected() {
return mCachedDevice.getBondState() == BluetoothDevice.BOND_BONDED
&& mCachedDevice.isConnected();
}
}

View File

@@ -41,6 +41,9 @@ public class BluetoothMediaManager extends MediaManager implements BluetoothCall
private static final String TAG = "BluetoothMediaManager";
private final DeviceAttributeChangeCallback mDeviceAttributeChangeCallback =
new DeviceAttributeChangeCallback();
private LocalBluetoothManager mLocalBluetoothManager;
private LocalBluetoothProfileManager mProfileManager;
private CachedBluetoothDeviceManager mCachedBluetoothDeviceManager;
@@ -65,7 +68,10 @@ public class BluetoothMediaManager extends MediaManager implements BluetoothCall
mLocalBluetoothManager.getEventManager().registerCallback(this);
buildBluetoothDeviceList();
dispatchDeviceListAdded();
addServiceListenerIfNecessary();
}
private void addServiceListenerIfNecessary() {
// The profile may not ready when calling startScan().
// Device status are all disconnected since profiles are not ready to connected.
// In this case, we observe onServiceConnected() in LocalBluetoothProfileManager.
@@ -78,18 +84,18 @@ public class BluetoothMediaManager extends MediaManager implements BluetoothCall
private void buildBluetoothDeviceList() {
mMediaDevices.clear();
addConnectedA2dpDevices();
addConnectedHearingAidDevices();
addConnectableA2dpDevices();
addConnectableHearingAidDevices();
}
private void addConnectedA2dpDevices() {
private void addConnectableA2dpDevices() {
final A2dpProfile a2dpProfile = mProfileManager.getA2dpProfile();
if (a2dpProfile == null) {
Log.w(TAG, "addConnectedA2dpDevices() a2dp profile is null!");
Log.w(TAG, "addConnectableA2dpDevices() a2dp profile is null!");
return;
}
final List<BluetoothDevice> devices = a2dpProfile.getConnectedDevices();
final List<BluetoothDevice> devices = a2dpProfile.getConnectableDevices();
for (BluetoothDevice device : devices) {
final CachedBluetoothDevice cachedDevice =
@@ -100,10 +106,12 @@ public class BluetoothMediaManager extends MediaManager implements BluetoothCall
continue;
}
Log.d(TAG, "addConnectedA2dpDevices() device : " + cachedDevice.getName()
+ ", is connected : " + cachedDevice.isConnected());
Log.d(TAG, "addConnectableA2dpDevices() device : " + cachedDevice.getName()
+ ", is connected : " + cachedDevice.isConnected()
+ ", is preferred : " + a2dpProfile.isPreferred(device));
if (cachedDevice.isConnected()) {
if (a2dpProfile.isPreferred(device)
&& BluetoothDevice.BOND_BONDED == cachedDevice.getBondState()) {
addMediaDevice(cachedDevice);
}
}
@@ -111,15 +119,15 @@ public class BluetoothMediaManager extends MediaManager implements BluetoothCall
mIsA2dpProfileReady = a2dpProfile.isProfileReady();
}
private void addConnectedHearingAidDevices() {
private void addConnectableHearingAidDevices() {
final HearingAidProfile hapProfile = mProfileManager.getHearingAidProfile();
if (hapProfile == null) {
Log.w(TAG, "addConnectedA2dpDevices() hap profile is null!");
Log.w(TAG, "addConnectableHearingAidDevices() hap profile is null!");
return;
}
final List<Long> devicesHiSyncIds = new ArrayList<>();
final List<BluetoothDevice> devices = hapProfile.getConnectedDevices();
final List<BluetoothDevice> devices = hapProfile.getConnectableDevices();
for (BluetoothDevice device : devices) {
final CachedBluetoothDevice cachedDevice =
@@ -130,13 +138,16 @@ public class BluetoothMediaManager extends MediaManager implements BluetoothCall
continue;
}
Log.d(TAG, "addConnectedHearingAidDevices() device : " + cachedDevice.getName()
+ ", is connected : " + cachedDevice.isConnected());
Log.d(TAG, "addConnectableHearingAidDevices() device : " + cachedDevice.getName()
+ ", is connected : " + cachedDevice.isConnected()
+ ", is preferred : " + hapProfile.isPreferred(device));
final long hiSyncId = hapProfile.getHiSyncId(device);
// device with same hiSyncId should not be shown in the UI.
// So do not add it into connectedDevices.
if (!devicesHiSyncIds.contains(hiSyncId) && cachedDevice.isConnected()) {
if (!devicesHiSyncIds.contains(hiSyncId) && hapProfile.isPreferred(device)
&& BluetoothDevice.BOND_BONDED == cachedDevice.getBondState()) {
devicesHiSyncIds.add(hiSyncId);
addMediaDevice(cachedDevice);
}
@@ -149,6 +160,7 @@ public class BluetoothMediaManager extends MediaManager implements BluetoothCall
MediaDevice mediaDevice = findMediaDevice(MediaDeviceUtils.getId(cachedDevice));
if (mediaDevice == null) {
mediaDevice = new BluetoothMediaDevice(mContext, cachedDevice);
cachedDevice.registerCallback(mDeviceAttributeChangeCallback);
mLastAddedDevice = mediaDevice;
mMediaDevices.add(mediaDevice);
}
@@ -157,6 +169,14 @@ public class BluetoothMediaManager extends MediaManager implements BluetoothCall
@Override
public void stopScan() {
mLocalBluetoothManager.getEventManager().unregisterCallback(this);
unregisterDeviceAttributeChangeCallback();
}
private void unregisterDeviceAttributeChangeCallback() {
for (MediaDevice device : mMediaDevices) {
((BluetoothMediaDevice) device).getCachedDevice()
.unregisterCallback(mDeviceAttributeChangeCallback);
}
}
@Override
@@ -164,12 +184,13 @@ public class BluetoothMediaManager extends MediaManager implements BluetoothCall
if (BluetoothAdapter.STATE_ON == bluetoothState) {
buildBluetoothDeviceList();
dispatchDeviceListAdded();
addServiceListenerIfNecessary();
} else if (BluetoothAdapter.STATE_OFF == bluetoothState) {
final List<MediaDevice> removeDevicesList = new ArrayList<>();
for (MediaDevice device : mMediaDevices) {
if (device instanceof BluetoothMediaDevice) {
removeDevicesList.add(device);
}
((BluetoothMediaDevice) device).getCachedDevice()
.unregisterCallback(mDeviceAttributeChangeCallback);
removeDevicesList.add(device);
}
mMediaDevices.removeAll(removeDevicesList);
dispatchDeviceListRemoved(removeDevicesList);
@@ -212,6 +233,7 @@ public class BluetoothMediaManager extends MediaManager implements BluetoothCall
private void removeMediaDevice(CachedBluetoothDevice cachedDevice) {
final MediaDevice mediaDevice = findMediaDevice(MediaDeviceUtils.getId(cachedDevice));
if (mediaDevice != null) {
cachedDevice.unregisterCallback(mDeviceAttributeChangeCallback);
mLastRemovedDevice = mediaDevice;
mMediaDevices.remove(mediaDevice);
}
@@ -230,12 +252,17 @@ public class BluetoothMediaManager extends MediaManager implements BluetoothCall
Log.d(TAG, "onProfileConnectionStateChanged() device: " + cachedDevice
+ ", state: " + state + ", bluetoothProfile: " + bluetoothProfile);
if (isCachedDeviceConnected(cachedDevice)) {
addMediaDevice(cachedDevice);
dispatchDeviceAdded(cachedDevice);
} else {
updateMediaDeviceListIfNecessary(cachedDevice);
}
private void updateMediaDeviceListIfNecessary(CachedBluetoothDevice cachedDevice) {
if (BluetoothDevice.BOND_NONE == cachedDevice.getBondState()) {
removeMediaDevice(cachedDevice);
dispatchDeviceRemoved(cachedDevice);
} else {
if (findMediaDevice(MediaDeviceUtils.getId(cachedDevice)) != null) {
dispatchDataChanged();
}
}
}
@@ -243,13 +270,7 @@ public class BluetoothMediaManager extends MediaManager implements BluetoothCall
public void onAclConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) {
Log.d(TAG, "onAclConnectionStateChanged() device: " + cachedDevice + ", state: " + state);
if (isCachedDeviceConnected(cachedDevice)) {
addMediaDevice(cachedDevice);
dispatchDeviceAdded(cachedDevice);
} else {
removeMediaDevice(cachedDevice);
dispatchDeviceRemoved(cachedDevice);
}
updateMediaDeviceListIfNecessary(cachedDevice);
}
@Override
@@ -281,4 +302,16 @@ public class BluetoothMediaManager extends MediaManager implements BluetoothCall
public void onServiceDisconnected() {
}
/**
* This callback is for update {@link BluetoothMediaDevice} summary when
* {@link CachedBluetoothDevice} connection state is changed.
*/
private class DeviceAttributeChangeCallback implements CachedBluetoothDevice.Callback {
@Override
public void onDeviceAttributesChanged() {
dispatchDataChanged();
}
}
}

View File

@@ -40,6 +40,11 @@ public class InfoMediaDevice extends MediaDevice {
return mRouteInfo.getName();
}
@Override
public String getSummary() {
return null;
}
@Override
public int getIcon() {
//TODO(b/121083246): This is not final icon for cast device, just for demo.
@@ -63,4 +68,9 @@ public class InfoMediaDevice extends MediaDevice {
public void disconnect() {
//TODO(b/121083246): disconnected last select device
}
@Override
public boolean isConnected() {
return true;
}
}

View File

@@ -58,7 +58,6 @@ public class LocalMediaManager implements BluetoothCallback {
private Context mContext;
private BluetoothMediaManager mBluetoothMediaManager;
private InfoMediaManager mInfoMediaManager;
private LocalBluetoothManager mLocalBluetoothManager;
@VisibleForTesting
@@ -97,7 +96,6 @@ public class LocalMediaManager implements BluetoothCallback {
mBluetoothMediaManager =
new BluetoothMediaManager(context, mLocalBluetoothManager, notification);
mInfoMediaManager = new InfoMediaManager(context, packageName, notification);
}
@VisibleForTesting
@@ -106,7 +104,6 @@ public class LocalMediaManager implements BluetoothCallback {
mContext = context;
mLocalBluetoothManager = localBluetoothManager;
mBluetoothMediaManager = bluetoothMediaManager;
mInfoMediaManager = infoMediaManager;
}
/**
@@ -115,6 +112,15 @@ public class LocalMediaManager implements BluetoothCallback {
*/
public void connectDevice(MediaDevice connectDevice) {
final MediaDevice device = getMediaDeviceById(mMediaDevices, connectDevice.getId());
if (device instanceof BluetoothMediaDevice) {
final CachedBluetoothDevice cachedDevice =
((BluetoothMediaDevice) device).getCachedDevice();
if (!cachedDevice.isConnected() && !cachedDevice.isBusy()) {
cachedDevice.connect(true);
return;
}
}
if (device == mCurrentConnectedDevice) {
Log.d(TAG, "connectDevice() this device all ready connected! : " + device.getName());
return;
@@ -150,9 +156,7 @@ public class LocalMediaManager implements BluetoothCallback {
public void startScan() {
mMediaDevices.clear();
mBluetoothMediaManager.registerCallback(mMediaDeviceCallback);
mInfoMediaManager.registerCallback(mMediaDeviceCallback);
mBluetoothMediaManager.startScan();
mInfoMediaManager.startScan();
}
private void addPhoneDeviceIfNecessary() {
@@ -186,9 +190,7 @@ public class LocalMediaManager implements BluetoothCallback {
*/
public void stopScan() {
mBluetoothMediaManager.unregisterCallback(mMediaDeviceCallback);
mInfoMediaManager.unregisterCallback(mMediaDeviceCallback);
mBluetoothMediaManager.stopScan();
mInfoMediaManager.stopScan();
}
/**
@@ -252,9 +254,17 @@ public class LocalMediaManager implements BluetoothCallback {
}
addPhoneDeviceIfNecessary();
mCurrentConnectedDevice = updateCurrentConnectedDevice();
updatePhoneMediaDeviceSummary();
dispatchDeviceListUpdate();
}
private void updatePhoneMediaDeviceSummary() {
if (mPhoneDevice != null) {
((PhoneMediaDevice) mPhoneDevice)
.updateSummary(mCurrentConnectedDevice == mPhoneDevice);
}
}
@Override
public void onDeviceRemoved(MediaDevice device) {
if (mMediaDevices.contains(device)) {
@@ -271,22 +281,23 @@ public class LocalMediaManager implements BluetoothCallback {
dispatchDeviceListUpdate();
}
@Override
public void onDeviceAttributesChanged() {
dispatchDeviceListUpdate();
}
@Override
public void onConnectedDeviceChanged(String id) {
final MediaDevice connectDevice = getMediaDeviceById(mMediaDevices, id);
if (connectDevice == mCurrentConnectedDevice) {
Log.d(TAG, "onConnectedDeviceChanged() this device all ready connected! : "
+ connectDevice.getName());
Log.d(TAG, "onConnectedDeviceChanged() this device all ready connected!");
return;
}
mCurrentConnectedDevice = connectDevice;
updatePhoneMediaDeviceSummary();
dispatchDeviceListUpdate();
}
@Override
public void onDeviceAttributesChanged() {
addPhoneDeviceIfNecessary();
removePhoneMediaDeviceIfNecessary();
dispatchDeviceListUpdate();
}
}

View File

@@ -34,9 +34,9 @@ public abstract class MediaDevice implements Comparable<MediaDevice> {
MediaDeviceType.TYPE_BLUETOOTH_DEVICE,
MediaDeviceType.TYPE_PHONE_DEVICE})
public @interface MediaDeviceType {
int TYPE_CAST_DEVICE = 1;
int TYPE_BLUETOOTH_DEVICE = 2;
int TYPE_PHONE_DEVICE = 3;
int TYPE_PHONE_DEVICE = 1;
int TYPE_CAST_DEVICE = 2;
int TYPE_BLUETOOTH_DEVICE = 3;
}
private int mConnectedRecord;
@@ -62,6 +62,13 @@ public abstract class MediaDevice implements Comparable<MediaDevice> {
*/
public abstract String getName();
/**
* Get summary from MediaDevice.
*
* @return summary of MediaDevice.
*/
public abstract String getSummary();
/**
* Get resource id of MediaDevice.
*
@@ -93,6 +100,13 @@ public abstract class MediaDevice implements Comparable<MediaDevice> {
*/
public abstract void disconnect();
/**
* According the MediaDevice type to check whether we are connected to this MediaDevice.
*
* @return Whether it is connected.
*/
public abstract boolean isConnected();
/**
* Rules:
* 1. If there is one of the connected devices identified as a carkit, this carkit will
@@ -103,9 +117,11 @@ public abstract class MediaDevice implements Comparable<MediaDevice> {
* 3. For devices with usage record.
* The most recent used one + device group with usage info sorted by how many times the
* device has been used.
* 4. Phone device always in the top and the connected Bluetooth devices, cast devices and
* phone device will be always above on the disconnect Bluetooth devices.
*
* So the device list will look like 4 slots ranked as below.
* Rule 1 + the most recently used device + Rule 3 + Rule 2
* So the device list will look like 5 slots ranked as below.
* Rule 4 + Rule 1 + the most recently used device + Rule 3 + Rule 2
* Any slot could be empty. And available device will belong to one of the slots.
*
* @return a negative integer, zero, or a positive integer
@@ -113,6 +129,21 @@ public abstract class MediaDevice implements Comparable<MediaDevice> {
*/
@Override
public int compareTo(MediaDevice another) {
// Check Bluetooth device is have same connection state
if (isConnected() ^ another.isConnected()) {
if (isConnected()) {
return -1;
} else {
return 1;
}
}
// Phone device always in the top.
if (mType == MediaDeviceType.TYPE_PHONE_DEVICE) {
return -1;
} else if (another.mType == MediaDeviceType.TYPE_PHONE_DEVICE) {
return 1;
}
// Check carkit
if (isCarKitDevice()) {
return -1;
@@ -138,7 +169,7 @@ public abstract class MediaDevice implements Comparable<MediaDevice> {
final String s2 = another.getName();
return s1.compareToIgnoreCase(s2);
}
// Both devices have never been used, the priority is Cast > Bluetooth > Phone
// Both devices have never been used, the priority is Phone > Cast > Bluetooth
return mType - another.mType;
}
@@ -149,4 +180,13 @@ public abstract class MediaDevice implements Comparable<MediaDevice> {
protected boolean isCarKitDevice() {
return false;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof MediaDevice)) {
return false;
}
final MediaDevice otherDevice = (MediaDevice) obj;
return otherDevice.getId().equals(getId());
}
}

View File

@@ -117,6 +117,14 @@ public abstract class MediaManager {
}
}
protected void dispatchDataChanged() {
synchronized (mCallbacks) {
for (MediaDeviceCallback callback : mCallbacks) {
callback.onDeviceAttributesChanged();
}
}
}
/**
* Callback for notifying device is added, removed and attributes changed.
*/
@@ -149,16 +157,17 @@ public abstract class MediaManager {
*/
void onDeviceListRemoved(List<MediaDevice> devices);
/**
* Callback for notifying MediaDevice attributes is changed.
*/
void onDeviceAttributesChanged();
/**
* Callback for notifying connected MediaDevice is changed.
*
* @param id the id of MediaDevice
*/
void onConnectedDeviceChanged(String id);
/**
* Callback for notifying that MediaDevice attributes
* (e.g: device name, connection state, subtitle) is changed.
*/
void onDeviceAttributesChanged();
}
}

View File

@@ -18,6 +18,7 @@ package com.android.settingslib.media;
import android.content.Context;
import android.util.Log;
import com.android.settingslib.R;
import com.android.settingslib.bluetooth.A2dpProfile;
import com.android.settingslib.bluetooth.HearingAidProfile;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
@@ -34,6 +35,7 @@ public class PhoneMediaDevice extends MediaDevice {
private LocalBluetoothProfileManager mProfileManager;
private LocalBluetoothManager mLocalBluetoothManager;
private String mSummary = "";
PhoneMediaDevice(Context context, LocalBluetoothManager localBluetoothManager) {
super(context, MediaDeviceType.TYPE_PHONE_DEVICE);
@@ -45,14 +47,17 @@ public class PhoneMediaDevice extends MediaDevice {
@Override
public String getName() {
return mContext
.getString(com.android.settingslib.R.string.media_transfer_phone_device_name);
return mContext.getString(R.string.media_transfer_this_device_name);
}
@Override
public String getSummary() {
return mSummary;
}
@Override
public int getIcon() {
//TODO(b/117129183): This is not final icon for phone device, just for demo.
return com.android.internal.R.drawable.ic_phone;
return R.drawable.ic_smartphone;
}
@Override
@@ -69,6 +74,7 @@ public class PhoneMediaDevice extends MediaDevice {
if (hapProfile != null && a2dpProfile != null) {
isConnected = hapProfile.setActiveDevice(null) && a2dpProfile.setActiveDevice(null);
updateSummary(true);
setConnectedRecord();
}
Log.d(TAG, "connect() device : " + getName() + ", is selected : " + isConnected);
@@ -77,6 +83,20 @@ public class PhoneMediaDevice extends MediaDevice {
@Override
public void disconnect() {
//TODO(b/117129183): disconnected last select device
updateSummary(false);
}
@Override
public boolean isConnected() {
return true;
}
/**
* According current active device is {@link PhoneMediaDevice} or not to update summary.
*/
public void updateSummary(boolean isActive) {
mSummary = isActive
? mContext.getString(R.string.bluetooth_active_no_battery_level)
: "";
}
}

View File

@@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.when;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
@@ -66,4 +67,20 @@ public class BluetoothMediaDeviceTest {
assertThat(mBluetoothMediaDevice.connect()).isFalse();
}
@Test
public void isCachedBluetoothDeviceConnected_deviceConnected_returnTrue() {
when(mDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
when(mDevice.isConnected()).thenReturn(true);
assertThat(mBluetoothMediaDevice.isConnected()).isTrue();
}
@Test
public void isCachedBluetoothDeviceConnected_deviceNotConnected_returnFalse() {
when(mDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
when(mDevice.isConnected()).thenReturn(false);
assertThat(mBluetoothMediaDevice.isConnected()).isFalse();
}
}

View File

@@ -87,15 +87,16 @@ public class BluetoothMediaManagerTest {
}
@Test
public void startScan_haveA2dpProfileConnectedBluetoothDevice_shouldAddDevice() {
public void startScan_haveA2dpProfileDeviceIsPreferredAndBonded_shouldAddDevice() {
final List<BluetoothDevice> devices = new ArrayList<>();
final CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class);
final BluetoothDevice bluetoothDevice = mock(BluetoothDevice.class);
devices.add(bluetoothDevice);
when(mA2dpProfile.getConnectedDevices()).thenReturn(devices);
when(mA2dpProfile.getConnectableDevices()).thenReturn(devices);
when(mCachedDeviceManager.findDevice(bluetoothDevice)).thenReturn(cachedDevice);
when(cachedDevice.isConnected()).thenReturn(true);
when(cachedDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
when(mA2dpProfile.isPreferred(bluetoothDevice)).thenReturn(true);
assertThat(mMediaManager.mMediaDevices).isEmpty();
mMediaManager.startScan();
@@ -103,15 +104,16 @@ public class BluetoothMediaManagerTest {
}
@Test
public void startScan_haveA2dpProfileDisconnectedBluetoothDevice_shouldNotAddDevice() {
public void startScan_haveA2dpProfileDeviceIsPreferredAndBondNone_shouldNotAddDevice() {
final List<BluetoothDevice> devices = new ArrayList<>();
final CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class);
final BluetoothDevice bluetoothDevice = mock(BluetoothDevice.class);
devices.add(bluetoothDevice);
when(mA2dpProfile.getConnectedDevices()).thenReturn(devices);
when(mA2dpProfile.getConnectableDevices()).thenReturn(devices);
when(mCachedDeviceManager.findDevice(bluetoothDevice)).thenReturn(cachedDevice);
when(cachedDevice.isConnected()).thenReturn(false);
when(cachedDevice.getBondState()).thenReturn(BluetoothDevice.BOND_NONE);
when(mA2dpProfile.isPreferred(bluetoothDevice)).thenReturn(true);
assertThat(mMediaManager.mMediaDevices).isEmpty();
mMediaManager.startScan();
@@ -122,7 +124,7 @@ public class BluetoothMediaManagerTest {
public void startScan_noA2dpProfileBluetoothDevice_shouldNotAddDevice() {
final List<BluetoothDevice> devices = new ArrayList<>();
when(mA2dpProfile.getConnectedDevices()).thenReturn(devices);
when(mA2dpProfile.getConnectableDevices()).thenReturn(devices);
assertThat(mMediaManager.mMediaDevices).isEmpty();
mMediaManager.startScan();
@@ -130,15 +132,16 @@ public class BluetoothMediaManagerTest {
}
@Test
public void startScan_haveHapProfileConnectedBluetoothDevice_shouldAddDevice() {
public void startScan_haveHapProfileDeviceIsPreferredAndBonded_shouldAddDevice() {
final List<BluetoothDevice> devices = new ArrayList<>();
final CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class);
final BluetoothDevice bluetoothDevice = mock(BluetoothDevice.class);
devices.add(bluetoothDevice);
when(mHapProfile.getConnectedDevices()).thenReturn(devices);
when(mHapProfile.getConnectableDevices()).thenReturn(devices);
when(mCachedDeviceManager.findDevice(bluetoothDevice)).thenReturn(cachedDevice);
when(cachedDevice.isConnected()).thenReturn(true);
when(cachedDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
when(mHapProfile.isPreferred(bluetoothDevice)).thenReturn(true);
assertThat(mMediaManager.mMediaDevices).isEmpty();
mMediaManager.startScan();
@@ -149,7 +152,7 @@ public class BluetoothMediaManagerTest {
public void startScan_noHapProfileBluetoothDevice_shouldNotAddDevice() {
final List<BluetoothDevice> devices = new ArrayList<>();
when(mHapProfile.getConnectedDevices()).thenReturn(devices);
when(mHapProfile.getConnectableDevices()).thenReturn(devices);
assertThat(mMediaManager.mMediaDevices).isEmpty();
mMediaManager.startScan();
@@ -230,9 +233,14 @@ public class BluetoothMediaManagerTest {
public void onBluetoothStateChanged_bluetoothStateIsOff_callOnDeviceListRemoved() {
final BluetoothMediaDevice device1 = mock(BluetoothMediaDevice.class);
final BluetoothMediaDevice device2 = mock(BluetoothMediaDevice.class);
final CachedBluetoothDevice cachedDevice1 = mock(CachedBluetoothDevice.class);
final CachedBluetoothDevice cachedDevice2 = mock(CachedBluetoothDevice.class);
mMediaManager.mMediaDevices.add(device1);
mMediaManager.mMediaDevices.add(device2);
when(device1.getCachedDevice()).thenReturn(cachedDevice1);
when(device2.getCachedDevice()).thenReturn(cachedDevice2);
mMediaManager.registerCallback(mCallback);
mMediaManager.onBluetoothStateChanged(BluetoothAdapter.STATE_OFF);
@@ -311,28 +319,30 @@ public class BluetoothMediaManagerTest {
}
@Test
public void onProfileConnectionStateChanged_cachedDeviceIsConnect_callOnDeviceAdded() {
final CachedBluetoothDevice device = mock(CachedBluetoothDevice.class);
when(device.isConnectedHearingAidDevice()).thenReturn(true);
when(device.isConnectedA2dpDevice()).thenReturn(true);
assertThat(mMediaManager.mMediaDevices).isEmpty();
mMediaManager.registerCallback(mCallback);
mMediaManager.onProfileConnectionStateChanged(device, 0, 0);
assertThat(mMediaManager.mMediaDevices).hasSize(1);
verify(mCallback).onDeviceAdded(any());
}
@Test
public void onProfileConnectionStateChanged_cachedDeviceIsDisconnect_callOnDeviceRemoved() {
public void onProfileConnectionStateChanged_cachedDeviceIsBonded_callDeviceAttributesChanged() {
final CachedBluetoothDevice device = mock(CachedBluetoothDevice.class);
final BluetoothMediaDevice bluetoothMediaDevice = mock(BluetoothMediaDevice.class);
mMediaManager.mMediaDevices.add(bluetoothMediaDevice);
when(device.isConnectedHearingAidDevice()).thenReturn(false);
when(device.isConnectedA2dpDevice()).thenReturn(false);
when(device.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
when(device.getAddress()).thenReturn(TEST_ADDRESS);
when(bluetoothMediaDevice.getId()).thenReturn(TEST_ADDRESS);
assertThat(mMediaManager.mMediaDevices).hasSize(1);
mMediaManager.registerCallback(mCallback);
mMediaManager.onProfileConnectionStateChanged(device, 0, 0);
assertThat(mMediaManager.mMediaDevices).hasSize(1);
verify(mCallback).onDeviceAttributesChanged();
}
@Test
public void onProfileConnectionStateChanged_cachedDeviceIsBondNone_callOnDeviceRemoved() {
final CachedBluetoothDevice device = mock(CachedBluetoothDevice.class);
final BluetoothMediaDevice bluetoothMediaDevice = mock(BluetoothMediaDevice.class);
mMediaManager.mMediaDevices.add(bluetoothMediaDevice);
when(device.getBondState()).thenReturn(BluetoothDevice.BOND_NONE);
when(device.getAddress()).thenReturn(TEST_ADDRESS);
when(bluetoothMediaDevice.getId()).thenReturn(TEST_ADDRESS);
@@ -345,28 +355,30 @@ public class BluetoothMediaManagerTest {
}
@Test
public void onAclConnectionStateChanged_cachedDeviceIsConnect_callOnDeviceAdded() {
final CachedBluetoothDevice device = mock(CachedBluetoothDevice.class);
when(device.isConnectedHearingAidDevice()).thenReturn(true);
when(device.isConnectedA2dpDevice()).thenReturn(true);
assertThat(mMediaManager.mMediaDevices).isEmpty();
mMediaManager.registerCallback(mCallback);
mMediaManager.onAclConnectionStateChanged(device, 0);
assertThat(mMediaManager.mMediaDevices).hasSize(1);
verify(mCallback).onDeviceAdded(any());
}
@Test
public void onAclConnectionStateChanged_cachedDeviceIsDisconnect_callOnDeviceRemoved() {
public void onAclConnectionStateChanged_cachedDeviceIsBonded_callDeviceAttributesChanged() {
final CachedBluetoothDevice device = mock(CachedBluetoothDevice.class);
final BluetoothMediaDevice bluetoothMediaDevice = mock(BluetoothMediaDevice.class);
mMediaManager.mMediaDevices.add(bluetoothMediaDevice);
when(device.isConnectedHearingAidDevice()).thenReturn(false);
when(device.isConnectedA2dpDevice()).thenReturn(false);
when(device.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
when(device.getAddress()).thenReturn(TEST_ADDRESS);
when(bluetoothMediaDevice.getId()).thenReturn(TEST_ADDRESS);
assertThat(mMediaManager.mMediaDevices).hasSize(1);
mMediaManager.registerCallback(mCallback);
mMediaManager.onAclConnectionStateChanged(device, 0);
assertThat(mMediaManager.mMediaDevices).hasSize(1);
verify(mCallback).onDeviceAttributesChanged();
}
@Test
public void onAclConnectionStateChanged_cachedDeviceIsBondNone_callOnDeviceRemoved() {
final CachedBluetoothDevice device = mock(CachedBluetoothDevice.class);
final BluetoothMediaDevice bluetoothMediaDevice = mock(BluetoothMediaDevice.class);
mMediaManager.mMediaDevices.add(bluetoothMediaDevice);
when(device.getBondState()).thenReturn(BluetoothDevice.BOND_NONE);
when(device.getAddress()).thenReturn(TEST_ADDRESS);
when(bluetoothMediaDevice.getId()).thenReturn(TEST_ADDRESS);

View File

@@ -28,6 +28,7 @@ import static org.mockito.Mockito.when;
import android.content.Context;
import com.android.settingslib.bluetooth.A2dpProfile;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.HearingAidProfile;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
@@ -112,6 +113,23 @@ public class LocalMediaManagerTest {
eq(LocalMediaManager.MediaDeviceState.STATE_DISCONNECTED));
}
@Test
public void connectDevice_bluetoothDeviceNotConnected_connectBluetoothDevice() {
final MediaDevice device = mock(BluetoothMediaDevice.class);
final CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class);
mLocalMediaManager.mMediaDevices.add(device);
when(device.getId()).thenReturn(TEST_DEVICE_ID_1);
when(((BluetoothMediaDevice) device).getCachedDevice()).thenReturn(cachedDevice);
when(cachedDevice.isConnected()).thenReturn(false);
when(cachedDevice.isBusy()).thenReturn(false);
mLocalMediaManager.registerCallback(mCallback);
mLocalMediaManager.connectDevice(device);
verify(cachedDevice).connect(true);
}
@Test
public void getMediaDeviceById_idExist_shouldReturnMediaDevice() {
final MediaDevice device1 = mock(MediaDevice.class);
@@ -321,15 +339,6 @@ public class LocalMediaManagerTest {
verify(mCallback).onDeviceListUpdate(any());
}
@Test
public void onDeviceAttributesChanged_shouldDispatchDeviceListUpdate() {
mLocalMediaManager.registerCallback(mCallback);
mLocalMediaManager.mMediaDeviceCallback.onDeviceAttributesChanged();
verify(mCallback).onDeviceListUpdate(any());
}
@Test
public void onConnectedDeviceChanged_connectedAndCurrentDeviceAreDifferent_notifyThemChanged() {
final MediaDevice device1 = mock(MediaDevice.class);
@@ -366,4 +375,13 @@ public class LocalMediaManagerTest {
verify(mCallback, never()).onDeviceListUpdate(any());
}
@Test
public void onDeviceAttributesChanged_shouldDispatchDeviceListUpdate() {
mLocalMediaManager.registerCallback(mCallback);
mLocalMediaManager.mMediaDeviceCallback.onDeviceAttributesChanged();
verify(mCallback).onDeviceListUpdate(any());
}
}

View File

@@ -114,6 +114,12 @@ public class MediaDeviceTest {
when(mCachedDevice1.getDevice()).thenReturn(mDevice1);
when(mCachedDevice2.getDevice()).thenReturn(mDevice2);
when(mCachedDevice3.getDevice()).thenReturn(mDevice3);
when(mCachedDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
when(mCachedDevice1.isConnected()).thenReturn(true);
when(mCachedDevice2.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
when(mCachedDevice2.isConnected()).thenReturn(true);
when(mCachedDevice3.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
when(mCachedDevice3.isConnected()).thenReturn(true);
when(mRouteInfo1.getId()).thenReturn(ROUTER_ID_1);
when(mRouteInfo2.getId()).thenReturn(ROUTER_ID_2);
when(mRouteInfo3.getId()).thenReturn(ROUTER_ID_3);
@@ -158,12 +164,25 @@ public class MediaDeviceTest {
}
@Test
public void compareTo_carKit_phone_carKitFirst() {
public void compareTo_carKit_phone_phoneFirst() {
when(mDevice1.getBluetoothClass()).thenReturn(mCarkitClass);
mMediaDevices.add(mPhoneMediaDevice);
mMediaDevices.add(mBluetoothMediaDevice1);
mMediaDevices.add(mPhoneMediaDevice);
assertThat(mMediaDevices.get(0)).isEqualTo(mBluetoothMediaDevice1);
Collections.sort(mMediaDevices, COMPARATOR);
assertThat(mMediaDevices.get(0)).isEqualTo(mPhoneMediaDevice);
}
@Test
public void compareTo_carKitIsDisConnected_nonCarKitBluetooth_nonCarKitBluetoothFirst() {
when(mDevice1.getBluetoothClass()).thenReturn(mHeadreeClass);
when(mDevice2.getBluetoothClass()).thenReturn(mCarkitClass);
when(mCachedDevice2.isConnected()).thenReturn(false);
mMediaDevices.add(mBluetoothMediaDevice1);
mMediaDevices.add(mBluetoothMediaDevice2);
assertThat(mMediaDevices.get(0)).isEqualTo(mBluetoothMediaDevice1);
Collections.sort(mMediaDevices, COMPARATOR);
assertThat(mMediaDevices.get(0)).isEqualTo(mBluetoothMediaDevice1);
}
@@ -178,6 +197,7 @@ public class MediaDeviceTest {
Collections.sort(mMediaDevices, COMPARATOR);
assertThat(mMediaDevices.get(0)).isEqualTo(mBluetoothMediaDevice2);
}
@Test
public void compareTo_connectionRecord_sortByRecord() {
mMediaDevices.add(mBluetoothMediaDevice1);
@@ -195,6 +215,25 @@ public class MediaDeviceTest {
assertThat(mMediaDevices.get(1)).isEqualTo(mBluetoothMediaDevice1);
}
@Test
public void compareTo_sortByRecord_connectedDeviceFirst() {
mMediaDevices.add(mBluetoothMediaDevice1);
mMediaDevices.add(mBluetoothMediaDevice2);
when(mCachedDevice2.isConnected()).thenReturn(false);
mBluetoothMediaDevice1.connect();
mBluetoothMediaDevice2.connect();
mBluetoothMediaDevice2.connect();
// Reset last selected record
ConnectionRecordManager.getInstance().setConnectionRecord(mContext, null, 0);
assertThat(mMediaDevices.get(0)).isEqualTo(mBluetoothMediaDevice1);
assertThat(mMediaDevices.get(1)).isEqualTo(mBluetoothMediaDevice2);
Collections.sort(mMediaDevices, COMPARATOR);
assertThat(mMediaDevices.get(0)).isEqualTo(mBluetoothMediaDevice1);
assertThat(mMediaDevices.get(1)).isEqualTo(mBluetoothMediaDevice2);
}
@Test
public void compareTo_info_bluetooth_infoFirst() {
mMediaDevices.add(mBluetoothMediaDevice1);
@@ -206,13 +245,13 @@ public class MediaDeviceTest {
}
@Test
public void compareTo_bluetooth_phone_bluetoothFirst() {
mMediaDevices.add(mPhoneMediaDevice);
public void compareTo_bluetooth_phone_phoneFirst() {
mMediaDevices.add(mBluetoothMediaDevice1);
mMediaDevices.add(mPhoneMediaDevice);
assertThat(mMediaDevices.get(0)).isEqualTo(mPhoneMediaDevice);
Collections.sort(mMediaDevices, COMPARATOR);
assertThat(mMediaDevices.get(0)).isEqualTo(mBluetoothMediaDevice1);
Collections.sort(mMediaDevices, COMPARATOR);
assertThat(mMediaDevices.get(0)).isEqualTo(mPhoneMediaDevice);
}
@Test
@@ -235,6 +274,17 @@ public class MediaDeviceTest {
assertThat(mMediaDevices.get(0)).isEqualTo(mBluetoothMediaDevice1);
}
@Test
public void compareTo_sortByAlphabet_connectDeviceFirst() {
mMediaDevices.add(mBluetoothMediaDevice2);
mMediaDevices.add(mBluetoothMediaDevice1);
when(mCachedDevice1.isConnected()).thenReturn(false);
assertThat(mMediaDevices.get(0)).isEqualTo(mBluetoothMediaDevice2);
Collections.sort(mMediaDevices, COMPARATOR);
assertThat(mMediaDevices.get(0)).isEqualTo(mBluetoothMediaDevice2);
}
// 1.mInfoMediaDevice1: Last Selected device
// 2.mBluetoothMediaDevice1: CarKit device
// 3.mInfoMediaDevice2: * 2 times usage
@@ -242,7 +292,7 @@ public class MediaDeviceTest {
// 5.mBluetoothMediaDevice2: * 2 times usage
// 6.mBluetoothMediaDevice3: * 1 time usage
// 7.mPhoneMediaDevice: * 0 time usage
// Order: 2 -> 1 -> 3 -> 5 -> 4 -> 6 -> 7
// Order: 7 -> 2 -> 1 -> 3 -> 5 -> 4 -> 6
@Test
public void compareTo_mixedDevices_carKitFirst() {
when(mDevice1.getBluetoothClass()).thenReturn(mCarkitClass);
@@ -264,13 +314,55 @@ public class MediaDeviceTest {
mInfoMediaDevice1.connect();
Collections.sort(mMediaDevices, COMPARATOR);
assertThat(mMediaDevices.get(0)).isEqualTo(mBluetoothMediaDevice1);
assertThat(mMediaDevices.get(0)).isEqualTo(mPhoneMediaDevice);
assertThat(mMediaDevices.get(1)).isEqualTo(mBluetoothMediaDevice1);
assertThat(mMediaDevices.get(2)).isEqualTo(mInfoMediaDevice1);
assertThat(mMediaDevices.get(3)).isEqualTo(mInfoMediaDevice2);
assertThat(mMediaDevices.get(4)).isEqualTo(mBluetoothMediaDevice2);
assertThat(mMediaDevices.get(5)).isEqualTo(mInfoMediaDevice3);
assertThat(mMediaDevices.get(6)).isEqualTo(mBluetoothMediaDevice3);
}
// 1.mInfoMediaDevice1: Last Selected device
// 2.mBluetoothMediaDevice1: CarKit device not connected
// 3.mInfoMediaDevice2: * 2 times usage
// 4.mInfoMediaDevice3: * 1 time usage
// 5.mBluetoothMediaDevice2: * 4 times usage not connected
// 6.mBluetoothMediaDevice3: * 1 time usage
// 7.mPhoneMediaDevice: * 0 time usage
// Order: 7 -> 1 -> 3 -> 4 -> 6 -> 2 -> 5
@Test
public void compareTo_mixedDevices_connectDeviceFirst() {
when(mDevice1.getBluetoothClass()).thenReturn(mCarkitClass);
when(mDevice2.getBluetoothClass()).thenReturn(mHeadreeClass);
when(mDevice3.getBluetoothClass()).thenReturn(mHeadreeClass);
when(mCachedDevice1.isConnected()).thenReturn(false);
when(mCachedDevice2.isConnected()).thenReturn(false);
mMediaDevices.add(mBluetoothMediaDevice1);
mMediaDevices.add(mBluetoothMediaDevice2);
mMediaDevices.add(mBluetoothMediaDevice3);
mMediaDevices.add(mInfoMediaDevice1);
mMediaDevices.add(mInfoMediaDevice2);
mMediaDevices.add(mInfoMediaDevice3);
mMediaDevices.add(mPhoneMediaDevice);
mBluetoothMediaDevice3.connect();
mBluetoothMediaDevice2.connect();
mBluetoothMediaDevice2.connect();
mBluetoothMediaDevice2.connect();
mBluetoothMediaDevice2.connect();
mInfoMediaDevice3.connect();
mInfoMediaDevice2.connect();
mInfoMediaDevice2.connect();
mInfoMediaDevice1.connect();
Collections.sort(mMediaDevices, COMPARATOR);
assertThat(mMediaDevices.get(0)).isEqualTo(mPhoneMediaDevice);
assertThat(mMediaDevices.get(1)).isEqualTo(mInfoMediaDevice1);
assertThat(mMediaDevices.get(2)).isEqualTo(mInfoMediaDevice2);
assertThat(mMediaDevices.get(3)).isEqualTo(mBluetoothMediaDevice2);
assertThat(mMediaDevices.get(4)).isEqualTo(mInfoMediaDevice3);
assertThat(mMediaDevices.get(5)).isEqualTo(mBluetoothMediaDevice3);
assertThat(mMediaDevices.get(6)).isEqualTo(mPhoneMediaDevice);
assertThat(mMediaDevices.get(3)).isEqualTo(mInfoMediaDevice3);
assertThat(mMediaDevices.get(4)).isEqualTo(mBluetoothMediaDevice3);
assertThat(mMediaDevices.get(5)).isEqualTo(mBluetoothMediaDevice1);
assertThat(mMediaDevices.get(6)).isEqualTo(mBluetoothMediaDevice2);
}
}

View File

@@ -110,6 +110,15 @@ public class MediaManagerTest {
verify(mCallback).onConnectedDeviceChanged(TEST_ID);
}
@Test
public void dispatchDataChanged_registerCallback_shouldDispatchCallback() {
mMediaManager.registerCallback(mCallback);
mMediaManager.dispatchDataChanged();
verify(mCallback).onDeviceAttributesChanged();
}
@Test
public void findMediaDevice_idExist_shouldReturnMediaDevice() {
mMediaManager.mMediaDevices.add(mDevice);

View File

@@ -23,6 +23,7 @@ import static org.mockito.Mockito.when;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import com.android.settingslib.R;
import com.android.settingslib.bluetooth.A2dpProfile;
import com.android.settingslib.bluetooth.HearingAidProfile;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
@@ -97,4 +98,19 @@ public class PhoneMediaDeviceTest {
assertThat(mPhoneMediaDevice.connect()).isFalse();
}
@Test
public void updateSummary_isActiveIsTrue_returnActiveString() {
mPhoneMediaDevice.updateSummary(true);
assertThat(mPhoneMediaDevice.getSummary())
.isEqualTo(mContext.getString(R.string.bluetooth_active_no_battery_level));
}
@Test
public void updateSummary_notActive_returnEmpty() {
mPhoneMediaDevice.updateSummary(false);
assertThat(mPhoneMediaDevice.getSummary()).isEmpty();
}
}