do not merge - Fix for issue 2184627 cherry picked from eclair-mr2
Bluetooth A2DP suspend-resume improvements.
This change will reduce the occurence rate of A2DP sink suspend resume failures observed in issues 2184627, 2181005 and possibly 2189628.
More robust suspend/resume logic.
Use only the suspend request to audio hardware to avoid having two concurent suspend resume control paths.
diff --git a/core/java/android/server/BluetoothA2dpService.java b/core/java/android/server/BluetoothA2dpService.java
index 9a2d6d9..ec3b2ff 100644
--- a/core/java/android/server/BluetoothA2dpService.java
+++ b/core/java/android/server/BluetoothA2dpService.java
@@ -72,8 +72,7 @@
private final AudioManager mAudioManager;
private final BluetoothService mBluetoothService;
private final BluetoothAdapter mAdapter;
- private boolean mSuspending;
- private boolean mResuming;
+ private int mTargetA2dpState;
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
@@ -151,8 +150,7 @@
if (mBluetoothService.isEnabled())
onBluetoothEnable();
- mSuspending = false;
- mResuming = false;
+ mTargetA2dpState = -1;
}
@Override
@@ -341,10 +339,7 @@
public synchronized boolean suspendSink(BluetoothDevice device) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH_ADMIN permission");
- if (DBG) log("suspendSink(" + device + "), mSuspending: "+mSuspending+", mResuming: "+mResuming);
- if (mSuspending) {
- return true;
- }
+ if (DBG) log("suspendSink(" + device + "), mTargetA2dpState: "+mTargetA2dpState);
if (device == null || mAudioDevices == null) {
return false;
}
@@ -353,28 +348,15 @@
if (path == null || state == null) {
return false;
}
- switch (state.intValue()) {
- case BluetoothA2dp.STATE_CONNECTED:
- if (mResuming) {
- mSuspending = true;
- }
- return true;
- case BluetoothA2dp.STATE_PLAYING:
- mAudioManager.setParameters("A2dpSuspended=true");
- mSuspending = suspendSinkNative(path);
- return mSuspending;
- default:
- return false;
- }
+
+ mTargetA2dpState = BluetoothA2dp.STATE_CONNECTED;
+ return checkSinkSuspendState(state.intValue());
}
public synchronized boolean resumeSink(BluetoothDevice device) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH_ADMIN permission");
- if (DBG) log("resumeSink(" + device + "), mResuming: "+mResuming+", mSuspending: "+mSuspending);
- if (mResuming) {
- return true;
- }
+ if (DBG) log("resumeSink(" + device + "), mTargetA2dpState: "+mTargetA2dpState);
if (device == null || mAudioDevices == null) {
return false;
}
@@ -383,19 +365,8 @@
if (path == null || state == null) {
return false;
}
- switch (state.intValue()) {
- case BluetoothA2dp.STATE_PLAYING:
- if (mSuspending) {
- mResuming = true;
- }
- return true;
- case BluetoothA2dp.STATE_CONNECTED:
- mResuming = resumeSinkNative(path);
- mAudioManager.setParameters("A2dpSuspended=false");
- return mResuming;
- default:
- return false;
- }
+ mTargetA2dpState = BluetoothA2dp.STATE_PLAYING;
+ return checkSinkSuspendState(state.intValue());
}
public synchronized BluetoothDevice[] getConnectedSinks() {
@@ -458,10 +429,6 @@
}
private void handleSinkStateChange(BluetoothDevice device, int prevState, int state) {
- if (state == BluetoothA2dp.STATE_DISCONNECTED) {
- mSuspending = false;
- mResuming = false;
- }
if (state != prevState) {
if (state == BluetoothA2dp.STATE_DISCONNECTED ||
state == BluetoothA2dp.STATE_DISCONNECTING) {
@@ -477,28 +444,11 @@
}
mAudioDevices.put(device, state);
- if (state == BluetoothA2dp.STATE_CONNECTED && prevState == BluetoothA2dp.STATE_PLAYING) {
- if (DBG) log("handleSinkStateChange() STATE_PLAYING -> STATE_CONNECTED: mSuspending: "
- +mSuspending+", mResuming: "+mResuming);
- if (mSuspending) {
- mSuspending = false;
- if (mResuming) {
- mResuming = false;
- resumeSink(device);
- }
- }
- }
- if (state == BluetoothA2dp.STATE_PLAYING && prevState == BluetoothA2dp.STATE_CONNECTED) {
- if (DBG) log("handleSinkStateChange() STATE_CONNECTED -> STATE_PLAYING: mSuspending: "
- +mSuspending+", mResuming: "+mResuming);
+ checkSinkSuspendState(state);
+ mTargetA2dpState = -1;
- if (mResuming) {
- mResuming = false;
- if (mSuspending) {
- mSuspending = false;
- suspendSink(device);
- }
- }
+ if (state == BluetoothA2dp.STATE_CONNECTING) {
+ mAudioManager.setParameters("A2dpSuspended=false");
}
Intent intent = new Intent(BluetoothA2dp.ACTION_SINK_STATE_CHANGED);
intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
@@ -527,6 +477,23 @@
return sinks;
}
+ private boolean checkSinkSuspendState(int state) {
+ boolean result = true;
+
+ if (state != mTargetA2dpState) {
+ if (state == BluetoothA2dp.STATE_PLAYING &&
+ mTargetA2dpState == BluetoothA2dp.STATE_CONNECTED) {
+ mAudioManager.setParameters("A2dpSuspended=true");
+ } else if (state == BluetoothA2dp.STATE_CONNECTED &&
+ mTargetA2dpState == BluetoothA2dp.STATE_PLAYING) {
+ mAudioManager.setParameters("A2dpSuspended=false");
+ } else {
+ result = false;
+ }
+ }
+ return result;
+ }
+
@Override
protected synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mAudioDevices.isEmpty()) return;