Update connected device summary

* Add dispatchAudioModeChanged() in CachedBluetoothDeviceManager for notify
  CacheBluetoothDevice to update their summary
* Add 5 combination that used to show the summary of CacheBluetoothDevice
  case 1: device battery not unknown and is a active device
          ex: show summary as "Active, 100% battery"
  case 2: device battery unkonwn and is a active device
          ex: show summary as "Active"
  case 3: device battery not unknown and not a active device
          ex: show summary as "100% battery"
  case 4: device battery unkonwn and not a active device
          ex: not show the summary
  case 5: device is in bonding state
          ex: show summary as "Pairing..."

Bug: 78318415
Test: make -j50 RunSettingsLibRoboTests
Change-Id: I70bf5386ff045ef4f07fb86fbdc8b943befc634c
This commit is contained in:
timhypeng
2018-03-29 14:23:21 +08:00
parent 1b25c9a89c
commit f050932e2a
4 changed files with 100 additions and 91 deletions

View File

@@ -490,6 +490,7 @@ public class BluetoothEventManager {
}
private void dispatchAudioModeChanged() {
mDeviceManager.dispatchAudioModeChanged();
synchronized (mCallbacks) {
for (BluetoothCallback callback : mCallbacks) {
callback.onAudioModeChanged();

View File

@@ -23,6 +23,7 @@ import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothUuid;
import android.content.Context;
import android.content.SharedPreferences;
import android.media.AudioManager;
import android.os.ParcelUuid;
import android.os.SystemClock;
import android.text.TextUtils;
@@ -51,6 +52,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
private final Context mContext;
private final LocalBluetoothAdapter mLocalAdapter;
private final LocalBluetoothProfileManager mProfileManager;
private final AudioManager mAudioManager;
private final BluetoothDevice mDevice;
//TODO: consider remove, BluetoothDevice.getName() is already cached
private String mName;
@@ -123,7 +125,6 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
private boolean mIsActiveDeviceA2dp = false;
private boolean mIsActiveDeviceHeadset = false;
private boolean mIsActiveDeviceHearingAid = false;
/**
* Describes the current device and profile for logging.
*
@@ -185,6 +186,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
mContext = context;
mLocalAdapter = adapter;
mProfileManager = profileManager;
mAudioManager = context.getSystemService(AudioManager.class);
mDevice = device;
mProfileConnectionState = new HashMap<LocalBluetoothProfile, Integer>();
fillData();
@@ -537,6 +539,12 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
}
}
/**
* Update the profile audio state.
*/
void onAudioModeChanged() {
dispatchAttributesChanged();
}
/**
* Get the device status as active or non-active per Bluetooth profile.
*
@@ -972,12 +980,14 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
/**
* @return resource for string that discribes the connection state of this device.
* case 1: idle or playing media, show "Active" on the only one A2DP active device.
* case 2: in phone call, show "Active" on the only one HFP active device
*/
public String getConnectionSummary() {
boolean profileConnected = false; // at least one profile is connected
boolean a2dpNotConnected = false; // A2DP is preferred but not connected
boolean hfpNotConnected = false; // HFP is preferred but not connected
boolean hearingAidNotConnected = false; // Hearing Aid is preferred but not connected
boolean profileConnected = false; // Updated as long as BluetoothProfile is connected
boolean a2dpConnected = true; // A2DP is connected
boolean hfpConnected = true; // HFP is connected
boolean hearingAidConnected = true; // Hearing Aid is connected
for (LocalBluetoothProfile profile : getProfiles()) {
int connectionStatus = getProfileConnectionState(profile);
@@ -994,13 +1004,13 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
case BluetoothProfile.STATE_DISCONNECTED:
if (profile.isProfileReady()) {
if ((profile instanceof A2dpProfile) ||
(profile instanceof A2dpSinkProfile)){
a2dpNotConnected = true;
(profile instanceof A2dpSinkProfile)) {
a2dpConnected = false;
} else if ((profile instanceof HeadsetProfile) ||
(profile instanceof HfpClientProfile)) {
hfpNotConnected = true;
} else if (profile instanceof HearingAidProfile) {
hearingAidNotConnected = true;
(profile instanceof HfpClientProfile)) {
hfpConnected = false;
} else if (profile instanceof HearingAidProfile) {
hearingAidConnected = false;
}
}
break;
@@ -1019,65 +1029,50 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
com.android.settingslib.Utils.formatPercentage(batteryLevel);
}
// Prepare the string for the Active Device summary
String[] activeDeviceStringsArray = mContext.getResources().getStringArray(
R.array.bluetooth_audio_active_device_summaries);
String activeDeviceString = activeDeviceStringsArray[0]; // Default value: not active
if (mIsActiveDeviceA2dp && mIsActiveDeviceHeadset) {
activeDeviceString = activeDeviceStringsArray[1]; // Active for Media and Phone
} else {
if (mIsActiveDeviceA2dp) {
activeDeviceString = activeDeviceStringsArray[2]; // Active for Media only
}
if (mIsActiveDeviceHeadset) {
activeDeviceString = activeDeviceStringsArray[3]; // Active for Phone only
}
}
if (!hearingAidNotConnected && mIsActiveDeviceHearingAid) {
activeDeviceString = activeDeviceStringsArray[1];
return mContext.getString(R.string.bluetooth_connected, activeDeviceString);
}
int stringRes = R.string.bluetooth_pairing;
//when profile is connected, information would be available
if (profileConnected) {
if (a2dpNotConnected && hfpNotConnected) {
if (a2dpConnected || hfpConnected || hearingAidConnected) {
//contain battery information
if (batteryLevelPercentageString != null) {
return mContext.getString(
R.string.bluetooth_connected_no_headset_no_a2dp_battery_level,
batteryLevelPercentageString, activeDeviceString);
//device is in phone call
if (com.android.settingslib.Utils.isAudioModeOngoingCall(mContext)) {
if (mIsActiveDeviceHeadset) {
stringRes = R.string.bluetooth_active_battery_level;
} else {
stringRes = R.string.bluetooth_battery_level;
}
} else {//device is not in phone call(ex. idle or playing media)
//need to check if A2DP and HearingAid are exclusive
if (mIsActiveDeviceHearingAid || mIsActiveDeviceA2dp) {
stringRes = R.string.bluetooth_active_battery_level;
} else {
stringRes = R.string.bluetooth_battery_level;
}
}
} else {
return mContext.getString(R.string.bluetooth_connected_no_headset_no_a2dp,
activeDeviceString);
//no battery information
if (com.android.settingslib.Utils.isAudioModeOngoingCall(mContext)) {
if (mIsActiveDeviceHeadset) {
stringRes = R.string.bluetooth_active_no_battery_level;
}
} else {
if (mIsActiveDeviceHearingAid || mIsActiveDeviceA2dp) {
stringRes = R.string.bluetooth_active_no_battery_level;
}
}
}
} else if (a2dpNotConnected) {
} else {//unknown profile with battery information
if (batteryLevelPercentageString != null) {
return mContext.getString(R.string.bluetooth_connected_no_a2dp_battery_level,
batteryLevelPercentageString, activeDeviceString);
} else {
return mContext.getString(R.string.bluetooth_connected_no_a2dp,
activeDeviceString);
}
} else if (hfpNotConnected) {
if (batteryLevelPercentageString != null) {
return mContext.getString(R.string.bluetooth_connected_no_headset_battery_level,
batteryLevelPercentageString, activeDeviceString);
} else {
return mContext.getString(R.string.bluetooth_connected_no_headset,
activeDeviceString);
}
} else {
if (batteryLevelPercentageString != null) {
return mContext.getString(R.string.bluetooth_connected_battery_level,
batteryLevelPercentageString, activeDeviceString);
} else {
return mContext.getString(R.string.bluetooth_connected, activeDeviceString);
stringRes = R.string.bluetooth_battery_level;
}
}
}
return getBondState() == BluetoothDevice.BOND_BONDING ?
mContext.getString(R.string.bluetooth_pairing) : null;
return (stringRes != R.string.bluetooth_pairing
|| getBondState() == BluetoothDevice.BOND_BONDING)
? mContext.getString(stringRes, batteryLevelPercentageString)
: null;
}
/**

View File

@@ -358,6 +358,12 @@ public class CachedBluetoothDeviceManager {
}
}
public synchronized void dispatchAudioModeChanged() {
for (CachedBluetoothDevice cachedDevice : mCachedDevices) {
cachedDevice.onAudioModeChanged();
}
}
private void log(String msg) {
if (DEBUG) {
Log.d(TAG, msg);

View File

@@ -23,23 +23,25 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.robolectric.Shadows.shadowOf;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.media.AudioManager;
import com.android.settingslib.SettingsLibRobolectricTestRunner;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowAudioManager;
@RunWith(RobolectricTestRunner.class)
@Config(resourceDir = "../../res")
@RunWith(SettingsLibRobolectricTestRunner.class)
public class CachedBluetoothDeviceTest {
private final static String DEVICE_NAME = "TestName";
private final static String DEVICE_ALIAS = "TestAlias";
@@ -60,6 +62,7 @@ public class CachedBluetoothDeviceTest {
@Mock
private BluetoothDevice mDevice;
private CachedBluetoothDevice mCachedDevice;
private ShadowAudioManager mShadowAudioManager;
private Context mContext;
private int mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;
@@ -67,6 +70,7 @@ public class CachedBluetoothDeviceTest {
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
mShadowAudioManager = shadowOf(mContext.getSystemService(AudioManager.class));
when(mDevice.getAddress()).thenReturn(DEVICE_ADDRESS);
when(mAdapter.getBluetoothState()).thenReturn(BluetoothAdapter.STATE_ON);
when(mHfpProfile.isProfileReady()).thenReturn(true);
@@ -83,7 +87,7 @@ public class CachedBluetoothDeviceTest {
// Test without battery level
// Set PAN profile to be connected and test connection state summary
mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_CONNECTED);
assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Connected");
assertThat(mCachedDevice.getConnectionSummary()).isNull();
// Set PAN profile to be disconnected and test connection state summary
mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);
@@ -93,7 +97,7 @@ public class CachedBluetoothDeviceTest {
mBatteryLevel = 10;
// Set PAN profile to be connected and test connection state summary
mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_CONNECTED);
assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Connected, battery 10%");
assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("10% battery");
// Set PAN profile to be disconnected and test connection state summary
mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);
@@ -104,7 +108,7 @@ public class CachedBluetoothDeviceTest {
// Set PAN profile to be connected and test connection state summary
mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_CONNECTED);
assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Connected");
assertThat(mCachedDevice.getConnectionSummary()).isNull();
// Set PAN profile to be disconnected and test connection state summary
mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);
@@ -119,23 +123,23 @@ public class CachedBluetoothDeviceTest {
mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_CONNECTED);
assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Connected, battery 10%");
assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("10% battery");
// Disconnect HFP only and test connection state summary
mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(
"Connected (no phone), battery 10%");
"10% battery");
// Disconnect A2DP only and test connection state summary
mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(
"Connected (no media), battery 10%");
"10% battery");
// Disconnect both HFP and A2DP and test connection state summary
mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(
"Connected (no phone or media), battery 10%");
"10% battery");
// Disconnect all profiles and test connection state summary
mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);
@@ -147,16 +151,16 @@ public class CachedBluetoothDeviceTest {
// Test without battery level
// Set A2DP profile to be connected and test connection state summary
mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Connected");
assertThat(mCachedDevice.getConnectionSummary()).isNull();
// Set device as Active for A2DP and test connection state summary
mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP);
assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Connected, active(media)");
assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active");
// Test with battery level
mBatteryLevel = 10;
assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(
"Connected, battery 10%, active(media)");
assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(
"Active, 10% battery");
// Set A2DP profile to be disconnected and test connection state summary
mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
@@ -167,7 +171,7 @@ public class CachedBluetoothDeviceTest {
// Set A2DP profile to be connected, Active and test connection state summary
mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP);
assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Connected, active(media)");
assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active");
// Set A2DP profile to be disconnected and test connection state summary
mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
@@ -179,16 +183,18 @@ public class CachedBluetoothDeviceTest {
// Test without battery level
// Set HFP profile to be connected and test connection state summary
mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Connected");
assertThat(mCachedDevice.getConnectionSummary()).isNull();
// Set device as Active for HFP and test connection state summary
mCachedDevice.onAudioModeChanged();
mShadowAudioManager.setMode(AudioManager.MODE_IN_CALL);
mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEADSET);
assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Connected, active(phone)");
assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active");
// Test with battery level
mBatteryLevel = 10;
assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(
"Connected, battery 10%, active(phone)");
assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(
"Active, 10% battery");
// Set HFP profile to be disconnected and test connection state summary
mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
@@ -199,7 +205,7 @@ public class CachedBluetoothDeviceTest {
// Set HFP profile to be connected, Active and test connection state summary
mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEADSET);
assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Connected, active(phone)");
assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active");
// Set HFP profile to be disconnected and test connection state summary
mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
@@ -211,15 +217,16 @@ public class CachedBluetoothDeviceTest {
// Test without battery level
// Set Hearing Aid profile to be connected and test connection state summary
mCachedDevice.onProfileStateChanged(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Connected");
assertThat(mCachedDevice.getConnectionSummary()).isNull();
// Set device as Active for Hearing Aid and test connection state summary
mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEARING_AID);
assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Connected, active");
assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active");
// Set Hearing Aid profile to be disconnected and test connection state summary
mCachedDevice.onActiveDeviceChanged(false, BluetoothProfile.HEARING_AID);
mCachedDevice.onProfileStateChanged(mHearingAidProfile, BluetoothProfile.STATE_DISCONNECTED);
mCachedDevice.
onProfileStateChanged(mHearingAidProfile, BluetoothProfile.STATE_DISCONNECTED);
assertThat(mCachedDevice.getConnectionSummary()).isNull();
}
@@ -229,23 +236,23 @@ public class CachedBluetoothDeviceTest {
// Set A2DP and HFP profiles to be connected and test connection state summary
mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Connected");
assertThat(mCachedDevice.getConnectionSummary()).isNull();
// Set device as Active for A2DP and HFP and test connection state summary
mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP);
mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEADSET);
assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Connected, active");
assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active");
// Test with battery level
mBatteryLevel = 10;
assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(
"Connected, battery 10%, active");
"Active, 10% battery");
// Disconnect A2DP only and test connection state summary
mCachedDevice.onActiveDeviceChanged(false, BluetoothProfile.A2DP);
mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(
"Connected (no media), battery 10%, active(phone)");
"10% battery");
// Disconnect HFP only and test connection state summary
mCachedDevice.onActiveDeviceChanged(false, BluetoothProfile.HEADSET);
@@ -253,7 +260,7 @@ public class CachedBluetoothDeviceTest {
mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP);
assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(
"Connected (no phone), battery 10%, active(media)");
"Active, 10% battery");
// Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level
mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;
@@ -262,7 +269,7 @@ public class CachedBluetoothDeviceTest {
mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP);
mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEADSET);
assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Connected, active");
assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active");
// Set A2DP and HFP profiles to be disconnected and test connection state summary
mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);