summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/com/android/bluetooth/a2dp/A2dpCodecConfig.java12
-rw-r--r--src/com/android/bluetooth/a2dp/A2dpService.java22
-rw-r--r--src/com/android/bluetooth/btservice/Config.java8
-rw-r--r--src/com/android/bluetooth/hearingaid/HearingAidNativeInterface.java24
-rw-r--r--src/com/android/bluetooth/hearingaid/HearingAidService.java63
-rw-r--r--src/com/android/bluetooth/hearingaid/HearingAidStateMachine.java33
-rw-r--r--src/com/android/bluetooth/hfp/HeadsetPhoneState.java122
-rw-r--r--src/com/android/bluetooth/hfp/HeadsetService.java6
-rw-r--r--src/com/android/bluetooth/hfp/HeadsetStateMachine.java3
-rw-r--r--src/com/android/bluetooth/map/BluetoothMapService.java26
-rw-r--r--src/com/android/bluetooth/newavrcp/AvrcpTargetService.java14
-rw-r--r--src/com/android/bluetooth/newavrcp/AvrcpVolumeManager.java19
-rw-r--r--src/com/android/bluetooth/newavrcp/MediaPlayerList.java10
-rw-r--r--src/com/android/bluetooth/newavrcp/MediaPlayerWrapper.java30
14 files changed, 174 insertions, 218 deletions
diff --git a/src/com/android/bluetooth/a2dp/A2dpCodecConfig.java b/src/com/android/bluetooth/a2dp/A2dpCodecConfig.java
index 4de89dfb..5da084f4 100644
--- a/src/com/android/bluetooth/a2dp/A2dpCodecConfig.java
+++ b/src/com/android/bluetooth/a2dp/A2dpCodecConfig.java
@@ -67,8 +67,16 @@ class A2dpCodecConfig {
// Set the mandatory codec's priority to default, and remove the rest
for (int i = 0; i < codecConfigArray.length; i++) {
BluetoothCodecConfig codecConfig = codecConfigArray[i];
- if (!codecConfig.isMandatoryCodec()) {
+ if (codecConfig == null || !codecConfig.isMandatoryCodec()) {
codecConfigArray[i] = null;
+ } else {
+ /* Rebuild SBC selectable codec with Dual Channel (SBC HD audio) */
+ codecConfigArray[i] = new BluetoothCodecConfig(
+ BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC, mA2dpSourceCodecPrioritySbc,
+ BluetoothCodecConfig.SAMPLE_RATE_NONE,
+ BluetoothCodecConfig.BITS_PER_SAMPLE_NONE,
+ BluetoothCodecConfig.CHANNEL_MODE_DUAL_CHANNEL, 0 /* codecSpecific1 */,
+ 0 /* codecSpecific2 */, 0 /* codecSpecific3 */, 0 /* codecSpecific4 */);
}
}
@@ -83,7 +91,7 @@ class A2dpCodecConfig {
// Set the mandatory codec's priority to highest, and remove the rest
for (int i = 0; i < codecConfigArray.length; i++) {
BluetoothCodecConfig codecConfig = codecConfigArray[i];
- if (codecConfig.isMandatoryCodec()) {
+ if (codecConfig != null && codecConfig.isMandatoryCodec()) {
codecConfig.setCodecPriority(BluetoothCodecConfig.CODEC_PRIORITY_HIGHEST);
} else {
codecConfigArray[i] = null;
diff --git a/src/com/android/bluetooth/a2dp/A2dpService.java b/src/com/android/bluetooth/a2dp/A2dpService.java
index 16188899..0fc50088 100644
--- a/src/com/android/bluetooth/a2dp/A2dpService.java
+++ b/src/com/android/bluetooth/a2dp/A2dpService.java
@@ -511,7 +511,14 @@ public class A2dpService extends ProfileService {
}
// Make sure the Audio Manager knows the previous Active device is disconnected,
// and the new Active device is connected.
+ // Also, mute and unmute the output during the switch to avoid audio glitches.
+ boolean wasMuted = false;
if (previousActiveDevice != null) {
+ if (!mAudioManager.isStreamMute(AudioManager.STREAM_MUSIC)) {
+ mAudioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC,
+ AudioManager.ADJUST_MUTE, 0);
+ wasMuted = true;
+ }
mAudioManager.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
previousActiveDevice, BluetoothProfile.STATE_DISCONNECTED,
BluetoothProfile.A2DP, true, -1);
@@ -533,6 +540,10 @@ public class A2dpService extends ProfileService {
// change, so the Audio Service can reset accordingly the audio
// feeding parameters in the Audio HAL to the Bluetooth stack.
mAudioManager.handleBluetoothA2dpDeviceConfigChange(mActiveDevice);
+ if (wasMuted) {
+ mAudioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC,
+ AudioManager.ADJUST_UNMUTE, 0);
+ }
}
}
return true;
@@ -922,7 +933,10 @@ public class A2dpService extends ProfileService {
BluetoothCodecStatus codecStatus = sm.getCodecStatus();
if (codecStatus != null) {
for (BluetoothCodecConfig config : codecStatus.getCodecsSelectableCapabilities()) {
- if (!config.isMandatoryCodec()) {
+ boolean isMandatoryCodecWithDualChannel = (config.isMandatoryCodec()
+ && (config.getChannelMode() & config.CHANNEL_MODE_DUAL_CHANNEL)
+ == config.CHANNEL_MODE_DUAL_CHANNEL);
+ if (config != null && !config.isMandatoryCodec() || isMandatoryCodecWithDualChannel) {
supportsOptional = true;
break;
}
@@ -930,11 +944,11 @@ public class A2dpService extends ProfileService {
}
}
if (previousSupport == BluetoothA2dp.OPTIONAL_CODECS_SUPPORT_UNKNOWN
- || supportsOptional != (previousSupport
- == BluetoothA2dp.OPTIONAL_CODECS_SUPPORTED)) {
+ || previousSupport == BluetoothA2dp.OPTIONAL_CODECS_NOT_SUPPORTED) {
setSupportsOptionalCodecs(device, supportsOptional);
}
- if (supportsOptional) {
+ if (supportsOptional
+ || previousSupport == BluetoothA2dp.OPTIONAL_CODECS_SUPPORTED) {
int enabled = getOptionalCodecsEnabled(device);
if (enabled == BluetoothA2dp.OPTIONAL_CODECS_PREF_ENABLED) {
enableOptionalCodecs(device);
diff --git a/src/com/android/bluetooth/btservice/Config.java b/src/com/android/bluetooth/btservice/Config.java
index ae65863f..8a9c0a1f 100644
--- a/src/com/android/bluetooth/btservice/Config.java
+++ b/src/com/android/bluetooth/btservice/Config.java
@@ -21,6 +21,7 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Resources;
import android.provider.Settings;
+import android.util.FeatureFlagUtils;
import android.util.Log;
import com.android.bluetooth.R;
@@ -117,6 +118,13 @@ public class Config {
ArrayList<Class> profiles = new ArrayList<>(PROFILE_SERVICES_AND_FLAGS.length);
for (ProfileConfig config : PROFILE_SERVICES_AND_FLAGS) {
boolean supported = resources.getBoolean(config.mSupported);
+
+ if (!supported && (config.mClass == HearingAidService.class) && FeatureFlagUtils
+ .isEnabled(ctx, FeatureFlagUtils.HEARING_AID_SETTINGS)) {
+ Log.v(TAG, "Feature Flag enables support for HearingAidService");
+ supported = true;
+ }
+
if (supported && !isProfileDisabled(ctx, config.mMask)) {
Log.v(TAG, "Adding " + config.mClass.getSimpleName());
profiles.add(config.mClass);
diff --git a/src/com/android/bluetooth/hearingaid/HearingAidNativeInterface.java b/src/com/android/bluetooth/hearingaid/HearingAidNativeInterface.java
index 26036595..e735a881 100644
--- a/src/com/android/bluetooth/hearingaid/HearingAidNativeInterface.java
+++ b/src/com/android/bluetooth/hearingaid/HearingAidNativeInterface.java
@@ -105,6 +105,28 @@ public class HearingAidNativeInterface {
}
/**
+ * Add a hearing aid device to white list.
+ *
+ * @param device the remote device
+ * @return true on success, otherwise false.
+ */
+ @VisibleForTesting (otherwise = VisibleForTesting.PACKAGE_PRIVATE)
+ public boolean addToWhiteList(BluetoothDevice device) {
+ return addToWhiteListNative(getByteAddress(device));
+ }
+
+ /**
+ * Remove a hearing aid device from white list.
+ *
+ * @param device the remote device
+ * @return true on success, otherwise false.
+ */
+ @VisibleForTesting (otherwise = VisibleForTesting.PACKAGE_PRIVATE)
+ public boolean removeFromWhiteList(BluetoothDevice device) {
+ return removeFromWhiteListNative(getByteAddress(device));
+ }
+
+ /**
* Sets the HearingAid volume
* @param volume
*/
@@ -168,5 +190,7 @@ public class HearingAidNativeInterface {
private native void cleanupNative();
private native boolean connectHearingAidNative(byte[] address);
private native boolean disconnectHearingAidNative(byte[] address);
+ private native boolean addToWhiteListNative(byte[] address);
+ private native boolean removeFromWhiteListNative(byte[] address);
private native void setVolumeNative(int volume);
}
diff --git a/src/com/android/bluetooth/hearingaid/HearingAidService.java b/src/com/android/bluetooth/hearingaid/HearingAidService.java
index 7f2ed89b..704a3d59 100644
--- a/src/com/android/bluetooth/hearingaid/HearingAidService.java
+++ b/src/com/android/bluetooth/hearingaid/HearingAidService.java
@@ -56,6 +56,10 @@ public class HearingAidService extends ProfileService {
// Upper limit of all HearingAid devices: Bonded or Connected
private static final int MAX_HEARING_AID_STATE_MACHINES = 10;
private static HearingAidService sHearingAidService;
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ static int sConnectTimeoutForEachSideMs = 8000;
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ static int sCheckWhitelistTimeoutMs = 16000;
private AdapterService mAdapterService;
private HandlerThread mStateMachinesThread;
@@ -243,14 +247,6 @@ public class HearingAidService extends ProfileService {
}
}
- synchronized (mStateMachines) {
- HearingAidStateMachine smConnect = getOrCreateStateMachine(device);
- if (smConnect == null) {
- Log.e(TAG, "Cannot connect to " + device + " : no state machine");
- }
- smConnect.sendMessage(HearingAidStateMachine.CONNECT);
- }
-
for (BluetoothDevice storedDevice : mDeviceHiSyncIdMap.keySet()) {
if (device.equals(storedDevice)) {
continue;
@@ -263,14 +259,27 @@ public class HearingAidService extends ProfileService {
Log.e(TAG, "Ignored connect request for " + device + " : no state machine");
continue;
}
- sm.sendMessage(HearingAidStateMachine.CONNECT);
- }
- if (hiSyncId == BluetoothHearingAid.HI_SYNC_ID_INVALID
- && !device.equals(storedDevice)) {
- break;
+ sm.sendMessage(HearingAidStateMachine.CONNECT,
+ sConnectTimeoutForEachSideMs);
+ sm.sendMessageDelayed(HearingAidStateMachine.CHECK_WHITELIST_CONNECTION,
+ sCheckWhitelistTimeoutMs);
}
+ break;
}
}
+
+ synchronized (mStateMachines) {
+ HearingAidStateMachine smConnect = getOrCreateStateMachine(device);
+ if (smConnect == null) {
+ Log.e(TAG, "Cannot connect to " + device + " : no state machine");
+ } else {
+ smConnect.sendMessage(HearingAidStateMachine.CONNECT,
+ sConnectTimeoutForEachSideMs * 2);
+ smConnect.sendMessageDelayed(HearingAidStateMachine.CHECK_WHITELIST_CONNECTION,
+ sCheckWhitelistTimeoutMs);
+ }
+ }
+
return true;
}
@@ -399,6 +408,16 @@ public class HearingAidService extends ProfileService {
}
}
+ /**
+ * Get the HiSyncIdMap for testing
+ *
+ * @return mDeviceHiSyncIdMap
+ */
+ @VisibleForTesting
+ Map<BluetoothDevice, Long> getHiSyncIdMap() {
+ return mDeviceHiSyncIdMap;
+ }
+
int getConnectionState(BluetoothDevice device) {
enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
synchronized (mStateMachines) {
@@ -602,19 +621,24 @@ public class HearingAidService extends ProfileService {
if (DBG) {
Log.d(TAG, "Set Hearing Aid audio to disconnected");
}
- mAudioManager.setHearingAidDeviceConnectionState(mPreviousAudioDevice,
- BluetoothProfile.STATE_DISCONNECTED);
+ boolean suppressNoisyIntent =
+ (getConnectionState(mPreviousAudioDevice) == BluetoothProfile.STATE_CONNECTED);
+ mAudioManager.setBluetoothHearingAidDeviceConnectionState(
+ mPreviousAudioDevice, BluetoothProfile.STATE_DISCONNECTED,
+ suppressNoisyIntent, 0);
mPreviousAudioDevice = null;
} else {
if (DBG) {
Log.d(TAG, "Set Hearing Aid audio to connected");
}
if (mPreviousAudioDevice != null) {
- mAudioManager.setHearingAidDeviceConnectionState(mPreviousAudioDevice,
- BluetoothProfile.STATE_DISCONNECTED);
+ mAudioManager.setBluetoothHearingAidDeviceConnectionState(
+ mPreviousAudioDevice, BluetoothProfile.STATE_DISCONNECTED,
+ true, 0);
}
- mAudioManager.setHearingAidDeviceConnectionState(device,
- BluetoothProfile.STATE_CONNECTED);
+ mAudioManager.setBluetoothHearingAidDeviceConnectionState(
+ device, BluetoothProfile.STATE_CONNECTED,
+ true, 0);
mPreviousAudioDevice = device;
}
}
@@ -652,6 +676,7 @@ public class HearingAidService extends ProfileService {
if (bondState != BluetoothDevice.BOND_NONE) {
return;
}
+ mDeviceHiSyncIdMap.remove(device);
synchronized (mStateMachines) {
HearingAidStateMachine sm = mStateMachines.get(device);
if (sm == null) {
diff --git a/src/com/android/bluetooth/hearingaid/HearingAidStateMachine.java b/src/com/android/bluetooth/hearingaid/HearingAidStateMachine.java
index d02e1021..3e0d617a 100644
--- a/src/com/android/bluetooth/hearingaid/HearingAidStateMachine.java
+++ b/src/com/android/bluetooth/hearingaid/HearingAidStateMachine.java
@@ -69,13 +69,15 @@ final class HearingAidStateMachine extends StateMachine {
static final int CONNECT = 1;
static final int DISCONNECT = 2;
+ static final int CHECK_WHITELIST_CONNECTION = 3;
@VisibleForTesting
static final int STACK_EVENT = 101;
private static final int CONNECT_TIMEOUT = 201;
- // NOTE: the value is not "final" - it is modified in the unit tests
- @VisibleForTesting
- static int sConnectTimeoutMs = 30000; // 30s
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ static int sConnectTimeoutMs = 16000;
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ static int sDisconnectTimeoutMs = 16000;
private Disconnected mDisconnected;
private Connecting mConnecting;
@@ -172,6 +174,12 @@ final class HearingAidStateMachine extends StateMachine {
case DISCONNECT:
Log.w(TAG, "Disconnected: DISCONNECT ignored: " + mDevice);
break;
+ case CHECK_WHITELIST_CONNECTION:
+ if (mService.getConnectedDevices().isEmpty()) {
+ log("No device connected, remove this device from white list");
+ mNativeInterface.removeFromWhiteList(mDevice);
+ }
+ break;
case STACK_EVENT:
HearingAidStackEvent event = (HearingAidStackEvent) message.obj;
if (DBG) {
@@ -238,7 +246,9 @@ final class HearingAidStateMachine extends StateMachine {
public void enter() {
Log.i(TAG, "Enter Connecting(" + mDevice + "): "
+ messageWhatToString(getCurrentMessage().what));
- sendMessageDelayed(CONNECT_TIMEOUT, sConnectTimeoutMs);
+ int timeout = getCurrentMessage().arg1 != 0
+ ? getCurrentMessage().arg1 : sConnectTimeoutMs;
+ sendMessageDelayed(CONNECT_TIMEOUT, timeout);
mConnectionState = BluetoothProfile.STATE_CONNECTING;
broadcastConnectionState(mConnectionState, mLastConnectionState);
}
@@ -261,14 +271,13 @@ final class HearingAidStateMachine extends StateMachine {
deferMessage(message);
break;
case CONNECT_TIMEOUT:
- Log.w(TAG, "Connecting connection timeout: " + mDevice);
+ Log.w(TAG, "Connecting connection timeout: " + mDevice + ". Try whitelist");
mNativeInterface.disconnectHearingAid(mDevice);
- HearingAidStackEvent disconnectEvent =
- new HearingAidStackEvent(
- HearingAidStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED);
- disconnectEvent.device = mDevice;
- disconnectEvent.valueInt1 = HearingAidStackEvent.CONNECTION_STATE_DISCONNECTED;
- sendMessage(STACK_EVENT, disconnectEvent);
+ mNativeInterface.addToWhiteList(mDevice);
+ transitionTo(mDisconnected);
+ break;
+ case CHECK_WHITELIST_CONNECTION:
+ deferMessage(message);
break;
case DISCONNECT:
log("Connecting: connection canceled to " + mDevice);
@@ -325,7 +334,7 @@ final class HearingAidStateMachine extends StateMachine {
public void enter() {
Log.i(TAG, "Enter Disconnecting(" + mDevice + "): "
+ messageWhatToString(getCurrentMessage().what));
- sendMessageDelayed(CONNECT_TIMEOUT, sConnectTimeoutMs);
+ sendMessageDelayed(CONNECT_TIMEOUT, sDisconnectTimeoutMs);
mConnectionState = BluetoothProfile.STATE_DISCONNECTING;
broadcastConnectionState(mConnectionState, mLastConnectionState);
}
diff --git a/src/com/android/bluetooth/hfp/HeadsetPhoneState.java b/src/com/android/bluetooth/hfp/HeadsetPhoneState.java
index a0914384..bcf123cd 100644
--- a/src/com/android/bluetooth/hfp/HeadsetPhoneState.java
+++ b/src/com/android/bluetooth/hfp/HeadsetPhoneState.java
@@ -323,134 +323,18 @@ public class HeadsetPhoneState {
@Override
public void onSignalStrengthsChanged(SignalStrength signalStrength) {
-
int prevSignal = mCindSignal;
if (mCindService == HeadsetHalConstants.NETWORK_STATE_NOT_AVAILABLE) {
mCindSignal = 0;
- } else if (signalStrength.isGsm()) {
- mCindSignal = signalStrength.getLteLevel();
- if (mCindSignal == SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
- mCindSignal = gsmAsuToSignal(signalStrength);
- } else {
- // SignalStrength#getLteLevel returns the scale from 0-4
- // Bluetooth signal scales at 0-5
- // Let's match up the larger side
- mCindSignal++;
- }
} else {
- mCindSignal = cdmaDbmEcioToSignal(signalStrength);
+ mCindSignal = signalStrength.getLevel() + 1;
}
-
- // network signal strength is scaled to BT 1-5 levels.
+ // +CIND "signal" indicator is always between 0 to 5
+ mCindSignal = Integer.max(Integer.min(mCindSignal, 5), 0);
// This results in a lot of duplicate messages, hence this check
if (prevSignal != mCindSignal) {
sendDeviceStateChanged();
}
}
-
- /* convert [0,31] ASU signal strength to the [0,5] expected by
- * bluetooth devices. Scale is similar to status bar policy
- */
- private int gsmAsuToSignal(SignalStrength signalStrength) {
- int asu = signalStrength.getGsmSignalStrength();
- if (asu == 99) {
- return 0;
- } else if (asu >= 16) {
- return 5;
- } else if (asu >= 8) {
- return 4;
- } else if (asu >= 4) {
- return 3;
- } else if (asu >= 2) {
- return 2;
- } else if (asu >= 1) {
- return 1;
- } else {
- return 0;
- }
- }
-
- /**
- * Convert the cdma / evdo db levels to appropriate icon level.
- * The scale is similar to the one used in status bar policy.
- *
- * @param signalStrength signal strength level
- * @return the icon level for remote device
- */
- private int cdmaDbmEcioToSignal(SignalStrength signalStrength) {
- int levelDbm = 0;
- int levelEcio = 0;
- int cdmaIconLevel = 0;
- int evdoIconLevel = 0;
- int cdmaDbm = signalStrength.getCdmaDbm();
- int cdmaEcio = signalStrength.getCdmaEcio();
-
- if (cdmaDbm >= -75) {
- levelDbm = 4;
- } else if (cdmaDbm >= -85) {
- levelDbm = 3;
- } else if (cdmaDbm >= -95) {
- levelDbm = 2;
- } else if (cdmaDbm >= -100) {
- levelDbm = 1;
- } else {
- levelDbm = 0;
- }
-
- // Ec/Io are in dB*10
- if (cdmaEcio >= -90) {
- levelEcio = 4;
- } else if (cdmaEcio >= -110) {
- levelEcio = 3;
- } else if (cdmaEcio >= -130) {
- levelEcio = 2;
- } else if (cdmaEcio >= -150) {
- levelEcio = 1;
- } else {
- levelEcio = 0;
- }
-
- cdmaIconLevel = (levelDbm < levelEcio) ? levelDbm : levelEcio;
-
- // STOPSHIP: Change back to getRilVoiceRadioTechnology
- if (mServiceState != null && (
- mServiceState.getRadioTechnology() == ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_0
- || mServiceState.getRadioTechnology()
- == ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_A)) {
- int evdoEcio = signalStrength.getEvdoEcio();
- int evdoSnr = signalStrength.getEvdoSnr();
- int levelEvdoEcio = 0;
- int levelEvdoSnr = 0;
-
- // Ec/Io are in dB*10
- if (evdoEcio >= -650) {
- levelEvdoEcio = 4;
- } else if (evdoEcio >= -750) {
- levelEvdoEcio = 3;
- } else if (evdoEcio >= -900) {
- levelEvdoEcio = 2;
- } else if (evdoEcio >= -1050) {
- levelEvdoEcio = 1;
- } else {
- levelEvdoEcio = 0;
- }
-
- if (evdoSnr > 7) {
- levelEvdoSnr = 4;
- } else if (evdoSnr > 5) {
- levelEvdoSnr = 3;
- } else if (evdoSnr > 3) {
- levelEvdoSnr = 2;
- } else if (evdoSnr > 1) {
- levelEvdoSnr = 1;
- } else {
- levelEvdoSnr = 0;
- }
-
- evdoIconLevel = (levelEvdoEcio < levelEvdoSnr) ? levelEvdoEcio : levelEvdoSnr;
- }
- // TODO(): There is a bug open regarding what should be sent.
- return (cdmaIconLevel > evdoIconLevel) ? cdmaIconLevel : evdoIconLevel;
- }
}
}
diff --git a/src/com/android/bluetooth/hfp/HeadsetService.java b/src/com/android/bluetooth/hfp/HeadsetService.java
index e7a7d639..6d16a6a2 100644
--- a/src/com/android/bluetooth/hfp/HeadsetService.java
+++ b/src/com/android/bluetooth/hfp/HeadsetService.java
@@ -1486,13 +1486,13 @@ public class HeadsetService extends ProfileService {
}
}
mStateMachinesThread.getThreadHandler().post(() -> {
- boolean shouldCallAudioBeActiveBefore = shouldCallAudioBeActive();
+ boolean isCallIdleBefore = mSystemInterface.isCallIdle();
mSystemInterface.getHeadsetPhoneState().setNumActiveCall(numActive);
mSystemInterface.getHeadsetPhoneState().setNumHeldCall(numHeld);
mSystemInterface.getHeadsetPhoneState().setCallState(callState);
// Suspend A2DP when call about is about to become active
if (callState != HeadsetHalConstants.CALL_STATE_DISCONNECTED
- && shouldCallAudioBeActive() && !shouldCallAudioBeActiveBefore) {
+ && !mSystemInterface.isCallIdle() && isCallIdleBefore) {
mSystemInterface.getAudioManager().setParameters("A2dpSuspended=true");
}
});
@@ -1501,7 +1501,7 @@ public class HeadsetService extends ProfileService {
new HeadsetCallState(numActive, numHeld, callState, number, type)));
mStateMachinesThread.getThreadHandler().post(() -> {
if (callState == HeadsetHalConstants.CALL_STATE_IDLE
- && !shouldCallAudioBeActive() && !isAudioOn()) {
+ && mSystemInterface.isCallIdle() && !isAudioOn()) {
// Resume A2DP when call ended and SCO is not connected
mSystemInterface.getAudioManager().setParameters("A2dpSuspended=false");
}
diff --git a/src/com/android/bluetooth/hfp/HeadsetStateMachine.java b/src/com/android/bluetooth/hfp/HeadsetStateMachine.java
index b1d2cfc7..d25d9edf 100644
--- a/src/com/android/bluetooth/hfp/HeadsetStateMachine.java
+++ b/src/com/android/bluetooth/hfp/HeadsetStateMachine.java
@@ -1201,7 +1201,8 @@ public class HeadsetStateMachine extends StateMachine {
// Set active device to current active SCO device when the current active device
// is different from mCurrentDevice. This is to accommodate active device state
// mis-match between native and Java.
- if (!mDevice.equals(mHeadsetService.getActiveDevice())) {
+ if (!mDevice.equals(mHeadsetService.getActiveDevice())
+ && !hasDeferredMessages(DISCONNECT_AUDIO)) {
mHeadsetService.setActiveDevice(mDevice);
}
setAudioParameters();
diff --git a/src/com/android/bluetooth/map/BluetoothMapService.java b/src/com/android/bluetooth/map/BluetoothMapService.java
index c00b39ba..bfb1d3fc 100644
--- a/src/com/android/bluetooth/map/BluetoothMapService.java
+++ b/src/com/android/bluetooth/map/BluetoothMapService.java
@@ -348,9 +348,7 @@ public class BluetoothMapService extends ProfileService {
updateMasInstancesHandler();
break;
case START_LISTENER:
- if (mAdapter.isEnabled()) {
- startSocketListeners(msg.arg1);
- }
+ startSocketListeners(msg.arg1);
break;
case MSG_MAS_CONNECT:
onConnectHandler(msg.arg1);
@@ -606,7 +604,6 @@ public class BluetoothMapService extends ProfileService {
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY);
- filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
filter.addAction(BluetoothDevice.ACTION_SDP_RECORD);
filter.addAction(ACTION_SHOW_MAPS_SETTINGS);
@@ -988,30 +985,11 @@ public class BluetoothMapService extends ProfileService {
private class MapBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
- if (DEBUG) {
- Log.d(TAG, "onReceive");
- }
String action = intent.getAction();
if (DEBUG) {
Log.d(TAG, "onReceive: " + action);
}
- if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
- int state =
- intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
- if (state == BluetoothAdapter.STATE_TURNING_OFF) {
- if (DEBUG) {
- Log.d(TAG, "STATE_TURNING_OFF");
- }
- sendShutdownMessage();
- } else if (state == BluetoothAdapter.STATE_ON) {
- if (DEBUG) {
- Log.d(TAG, "STATE_ON");
- }
- // start ServerSocket listener threads
- sendStartListenerMessage(-1);
- }
-
- } else if (action.equals(USER_CONFIRM_TIMEOUT_ACTION)) {
+ if (action.equals(USER_CONFIRM_TIMEOUT_ACTION)) {
if (DEBUG) {
Log.d(TAG, "USER_CONFIRM_TIMEOUT ACTION Received.");
}
diff --git a/src/com/android/bluetooth/newavrcp/AvrcpTargetService.java b/src/com/android/bluetooth/newavrcp/AvrcpTargetService.java
index c7029ce1..6a1d357d 100644
--- a/src/com/android/bluetooth/newavrcp/AvrcpTargetService.java
+++ b/src/com/android/bluetooth/newavrcp/AvrcpTargetService.java
@@ -65,6 +65,8 @@ public class AvrcpTargetService extends ProfileService {
MediaPlayerList.FolderUpdateCallback {
@Override
public void run(MediaData data) {
+ if (mNativeInterface == null) return;
+
boolean metadata = !Objects.equals(mCurrentData.metadata, data.metadata);
boolean state = !MediaPlayerWrapper.playstateEquals(mCurrentData.state, data.state);
boolean queue = !Objects.equals(mCurrentData.queue, data.queue);
@@ -81,6 +83,8 @@ public class AvrcpTargetService extends ProfileService {
@Override
public void run(boolean availablePlayers, boolean addressedPlayers,
boolean uids) {
+ if (mNativeInterface == null) return;
+
mNativeInterface.sendFolderUpdate(availablePlayers, addressedPlayers, uids);
}
}
@@ -140,17 +144,17 @@ public class AvrcpTargetService extends ProfileService {
Log.i(TAG, "Starting the AVRCP Target Service");
mCurrentData = new MediaData(null, null, null);
- mReceiver = new AvrcpBroadcastReceiver();
- IntentFilter filter = new IntentFilter();
- filter.addAction(BluetoothA2dp.ACTION_ACTIVE_DEVICE_CHANGED);
- registerReceiver(mReceiver, filter);
-
if (!SystemProperties.getBoolean(AVRCP_ENABLE_PROPERTY, true)) {
Log.w(TAG, "Skipping initialization of the new AVRCP Target Service");
sInstance = null;
return true;
}
+ mReceiver = new AvrcpBroadcastReceiver();
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(BluetoothA2dp.ACTION_ACTIVE_DEVICE_CHANGED);
+ registerReceiver(mReceiver, filter);
+
mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
sDeviceMaxVolume = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
diff --git a/src/com/android/bluetooth/newavrcp/AvrcpVolumeManager.java b/src/com/android/bluetooth/newavrcp/AvrcpVolumeManager.java
index 4b87fac6..2e2ce420 100644
--- a/src/com/android/bluetooth/newavrcp/AvrcpVolumeManager.java
+++ b/src/com/android/bluetooth/newavrcp/AvrcpVolumeManager.java
@@ -36,11 +36,12 @@ class AvrcpVolumeManager extends AudioDeviceCallback {
public static final boolean DEBUG = true;
// All volumes are stored at system volume values, not AVRCP values
- public static final String VOLUME_MAP = "bluetooth_volume_map";
- public static final String VOLUME_BLACKLIST = "absolute_volume_blacklist";
- public static final int AVRCP_MAX_VOL = 127;
- public static int sDeviceMaxVolume = 0;
- public static final int STREAM_MUSIC = AudioManager.STREAM_MUSIC;
+ private static final String VOLUME_MAP = "bluetooth_volume_map";
+ private static final String VOLUME_BLACKLIST = "absolute_volume_blacklist";
+ private static final int AVRCP_MAX_VOL = 127;
+ private static final int STREAM_MUSIC = AudioManager.STREAM_MUSIC;
+ private static int sDeviceMaxVolume = 0;
+ private static int sNewDeviceVolume = 0;
Context mContext;
AudioManager mAudioManager;
@@ -72,10 +73,9 @@ class AvrcpVolumeManager extends AudioDeviceCallback {
mAudioManager.avrcpSupportsAbsoluteVolume(device.getAddress(), mDeviceMap.get(device));
// Get the current system volume and try to get the preference volume
- int currVolume = mAudioManager.getStreamVolume(STREAM_MUSIC);
- int savedVolume = getVolume(device, currVolume);
+ int savedVolume = getVolume(device, sNewDeviceVolume);
- d("switchVolumeDevice: currVolume=" + currVolume + " savedVolume=" + savedVolume);
+ d("switchVolumeDevice: savedVolume=" + savedVolume);
// If absolute volume for the device is supported, set the volume for the device
if (mDeviceMap.get(device)) {
@@ -91,6 +91,7 @@ class AvrcpVolumeManager extends AudioDeviceCallback {
mAudioManager = audioManager;
mNativeInterface = nativeInterface;
sDeviceMaxVolume = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
+ sNewDeviceVolume = sDeviceMaxVolume / 2;
mAudioManager.registerAudioDeviceCallback(this, null);
@@ -194,7 +195,7 @@ class AvrcpVolumeManager extends AudioDeviceCallback {
mCurrentDevice = device;
}
- void deviceDisconnected(@NonNull BluetoothDevice device) {
+ synchronized void deviceDisconnected(@NonNull BluetoothDevice device) {
d("deviceDisconnected: device=" + device);
mDeviceMap.remove(device);
}
diff --git a/src/com/android/bluetooth/newavrcp/MediaPlayerList.java b/src/com/android/bluetooth/newavrcp/MediaPlayerList.java
index 1a10979c..74ea0393 100644
--- a/src/com/android/bluetooth/newavrcp/MediaPlayerList.java
+++ b/src/com/android/bluetooth/newavrcp/MediaPlayerList.java
@@ -152,7 +152,7 @@ public class MediaPlayerList {
for (BrowsedPlayerWrapper wrapper : players) {
// Generate new id and add the browsable player
if (!mMediaPlayerIds.containsKey(wrapper.getPackageName())) {
- mMediaPlayerIds.put(wrapper.getPackageName(), mMediaPlayerIds.size() + 1);
+ mMediaPlayerIds.put(wrapper.getPackageName(), getFreeMediaPlayerId());
}
d("Adding Browser Wrapper for " + wrapper.getPackageName() + " with id "
@@ -206,6 +206,12 @@ public class MediaPlayerList {
return BLUETOOTH_PLAYER_ID;
}
+ int getFreeMediaPlayerId() {
+ int id = 0;
+ while (mMediaPlayerIds.containsValue(++id)) {}
+ return id;
+ }
+
MediaPlayerWrapper getActivePlayer() {
return mMediaPlayers.get(mActivePlayerId);
}
@@ -405,7 +411,7 @@ public class MediaPlayerList {
// that key.
String packageName = controller.getPackageName();
if (!mMediaPlayerIds.containsKey(packageName)) {
- mMediaPlayerIds.put(packageName, mMediaPlayerIds.size() + 1);
+ mMediaPlayerIds.put(packageName, getFreeMediaPlayerId());
}
int playerId = mMediaPlayerIds.get(packageName);
diff --git a/src/com/android/bluetooth/newavrcp/MediaPlayerWrapper.java b/src/com/android/bluetooth/newavrcp/MediaPlayerWrapper.java
index e0b591ad..256e7714 100644
--- a/src/com/android/bluetooth/newavrcp/MediaPlayerWrapper.java
+++ b/src/com/android/bluetooth/newavrcp/MediaPlayerWrapper.java
@@ -53,7 +53,6 @@ class MediaPlayerWrapper {
private final Object mCallbackLock = new Object();
private Callback mRegisteredCallback = null;
-
protected MediaPlayerWrapper() {
mCurrentData = new MediaData(null, null, null);
}
@@ -122,16 +121,6 @@ class MediaPlayerWrapper {
}
Metadata getCurrentMetadata() {
- // Try to use the now playing list if the information exists.
- if (getActiveQueueID() != -1) {
- for (Metadata data : getCurrentQueue()) {
- if (data.mediaId.equals(Util.NOW_PLAYING_PREFIX + getActiveQueueID())) {
- d("getCurrentMetadata: Using playlist data: " + data.toString());
- return data.clone();
- }
- }
- }
-
return Util.toMetadata(getMetadata());
}
@@ -240,7 +229,7 @@ class MediaPlayerWrapper {
getPlaybackState(),
Util.toMetadataList(getQueue()));
- mControllerCallbacks = new MediaControllerListener(mLooper);
+ mControllerCallbacks = new MediaControllerListener(mMediaController, mLooper);
}
/**
@@ -260,14 +249,16 @@ class MediaPlayerWrapper {
void updateMediaController(MediaController newController) {
if (newController == mMediaController) return;
+ mMediaController = newController;
+
synchronized (mCallbackLock) {
if (mRegisteredCallback == null || mControllerCallbacks == null) {
+ d("Controller for " + mPackageName + " maybe is not activated.");
return;
}
}
mControllerCallbacks.cleanup();
- mMediaController = newController;
// Update the current data since it could be different on the new controller for the player
mCurrentData = new MediaData(
@@ -275,7 +266,7 @@ class MediaPlayerWrapper {
getPlaybackState(),
Util.toMetadataList(getQueue()));
- mControllerCallbacks = new MediaControllerListener(mLooper);
+ mControllerCallbacks = new MediaControllerListener(mMediaController, mLooper);
d("Controller for " + mPackageName + " was updated.");
}
@@ -295,7 +286,7 @@ class MediaPlayerWrapper {
synchronized (mCallbackLock) {
if (mRegisteredCallback == null) {
Log.e(TAG, mPackageName
- + "Trying to send an update with no registered callback");
+ + ": Trying to send an update with no registered callback");
return;
}
@@ -340,20 +331,23 @@ class MediaPlayerWrapper {
class MediaControllerListener extends MediaController.Callback {
private final Object mTimeoutHandlerLock = new Object();
private Handler mTimeoutHandler;
+ private MediaController mController;
- MediaControllerListener(Looper newLooper) {
+ MediaControllerListener(MediaController controller, Looper newLooper) {
synchronized (mTimeoutHandlerLock) {
mTimeoutHandler = new TimeoutHandler(newLooper);
+ mController = controller;
// Register the callbacks to execute on the same thread as the timeout thread. This
// prevents a race condition where a timeout happens at the same time as an update.
- mMediaController.registerCallback(this, mTimeoutHandler);
+ mController.registerCallback(this, mTimeoutHandler);
}
}
void cleanup() {
synchronized (mTimeoutHandlerLock) {
- mMediaController.unregisterCallback(this);
+ mController.unregisterCallback(this);
+ mController = null;
mTimeoutHandler.removeMessages(TimeoutHandler.MSG_TIMEOUT);
mTimeoutHandler = null;
}