From 7847211fb4699bf6018e29d214a918ed6657319b Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Mon, 21 May 2012 08:57:21 -0700 Subject: [PATCH] AudioManager: restore setBluetoothA2dpOn() method Remove deprecation on setBluetoothA2dpOn() method so that applications can override the default audio policy which is to use A2DP for media whenever connected. The request is not persistent and the default policy is restored when a new A2DP i ro wired headset connection occurs. Bug 6485897. Change-Id: I2a4b6b6bdba55f7b133e64f86d27c03eb86acfa4 --- media/java/android/media/AudioManager.java | 35 +++++++++++---- media/java/android/media/AudioService.java | 48 +++++++++++++++++++++ media/java/android/media/AudioSystem.java | 3 +- media/java/android/media/IAudioService.aidl | 4 ++ 4 files changed, 80 insertions(+), 10 deletions(-) diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index 16cfa926dbd73..6c7c160b14d27 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -1270,25 +1270,42 @@ public class AudioManager { } /** - * @param on set true to route A2DP audio to/from Bluetooth - * headset; false disable A2DP audio + * Allow or disallow use of Bluetooth A2DP for media. + *

The default behavior of the system is to use A2DP for media playback whenever an A2DP sink + * is connected. Applications can use this method to override this behavior. + * Note that the request will not persist after a wired headset or an A2DP sink is connected or + * disconnected: + * - Connection of an A2DP sink automatically enables use of A2DP. + * - Connection of a wired headset automatically disables use of A2DP. + * - Disconnection of a wired headset automatically enables use of A2DP if an A2DP sink is + * connected. + *

Requires Permission: + * {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS}. + * @param on set true to allow use of A2DP for media (default). + * false to disallow use of A2DP for media. * @deprecated Do not use. */ @Deprecated public void setBluetoothA2dpOn(boolean on){ + IAudioService service = getService(); + try { + service.setBluetoothA2dpOn(on); + } catch (RemoteException e) { + Log.e(TAG, "Dead object in setBluetoothA2dpOn", e); + } } /** - * Checks whether A2DP audio routing to the Bluetooth headset is on or off. + * Checks whether use of A2DP sinks is enabled for media. * - * @return true if A2DP audio is being routed to/from Bluetooth headset; - * false if otherwise + * @return true if use of A2DP is enabled for media, false otherwise. */ public boolean isBluetoothA2dpOn() { - if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP,"") - == AudioSystem.DEVICE_STATE_UNAVAILABLE) { + IAudioService service = getService(); + try { + return service.isBluetoothA2dpOn(); + } catch (RemoteException e) { + Log.e(TAG, "Dead object in isBluetoothA2dpOn", e); return false; - } else { - return true; } } diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java index da01c4424918a..5e338abf46c02 100644 --- a/media/java/android/media/AudioService.java +++ b/media/java/android/media/AudioService.java @@ -392,6 +392,10 @@ public class AudioService extends IAudioService.Stub implements OnFinished { private int mDeviceOrientation = Configuration.ORIENTATION_UNDEFINED; + // Request to override default use of A2DP for media. + private boolean mBluetoothA2dpEnabled; + private final Object mBluetoothA2dpEnabledLock = new Object(); + /////////////////////////////////////////////////////////////////////////// // Construction /////////////////////////////////////////////////////////////////////////// @@ -481,6 +485,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished { mMasterVolumeRamp = context.getResources().getIntArray( com.android.internal.R.array.config_masterVolumeRamp); + } private void createAudioSystemThread() { @@ -1651,6 +1656,21 @@ public class AudioService extends IAudioService.Stub implements OnFinished { return (mForcedUseForComm == AudioSystem.FORCE_BT_SCO); } + /** @see AudioManager#setBluetoothA2dpOn() */ + public void setBluetoothA2dpOn(boolean on) { + if (!checkAudioSettingsPermission("setBluetoothA2dpOn()")) { + return; + } + setBluetoothA2dpOnInt(on); + } + + /** @see AudioManager#isBluetoothA2dpOn() */ + public boolean isBluetoothA2dpOn() { + synchronized (mBluetoothA2dpEnabledLock) { + return mBluetoothA2dpEnabled; + } + } + /** @see AudioManager#startBluetoothSco() */ public void startBluetoothSco(IBinder cb){ if (!checkAudioSettingsPermission("startBluetoothSco()") || @@ -1673,6 +1693,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished { } } + private class ScoClient implements IBinder.DeathRecipient { private IBinder mCb; // To be notified of client's death private int mCreatorPid; @@ -2894,6 +2915,11 @@ public class AudioService extends IAudioService.Stub implements OnFinished { setOrientationForAudioSystem(); } + synchronized (mBluetoothA2dpEnabledLock) { + AudioSystem.setForceUse(AudioSystem.FOR_MEDIA, + mBluetoothA2dpEnabled ? + AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP); + } // indicate the end of reconfiguration phase to audio HAL AudioSystem.setParameters("restarting=false"); break; @@ -2976,6 +3002,9 @@ public class AudioService extends IAudioService.Stub implements OnFinished { // must be called synchronized on mConnectedDevices private void makeA2dpDeviceAvailable(String address) { + // enable A2DP before notifying A2DP connection to avoid unecessary processing in + // audio policy manager + setBluetoothA2dpOnInt(true); AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, AudioSystem.DEVICE_STATE_AVAILABLE, address); @@ -3177,7 +3206,15 @@ public class AudioService extends IAudioService.Stub implements OnFinished { } else { device = AudioSystem.DEVICE_OUT_WIRED_HEADPHONE; } + // enable A2DP before notifying headset disconnection to avoid glitches + if (state == 0) { + setBluetoothA2dpOnInt(true); + } handleDeviceConnection((state == 1), device, ""); + // disable A2DP after notifying headset connection to avoid glitches + if (state != 0) { + setBluetoothA2dpOnInt(false); + } } else if (action.equals(Intent.ACTION_ANALOG_AUDIO_DOCK_PLUG)) { state = intent.getIntExtra("state", 0); Log.v(TAG, "Broadcast Receiver: Got ACTION_ANALOG_AUDIO_DOCK_PLUG, state = "+state); @@ -4655,6 +4692,17 @@ public class AudioService extends IAudioService.Stub implements OnFinished { } + // Handles request to override default use of A2DP for media. + public void setBluetoothA2dpOnInt(boolean on) { + synchronized (mBluetoothA2dpEnabledLock) { + mBluetoothA2dpEnabled = on; + sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE, + AudioSystem.FOR_MEDIA, + mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP, + null, 0); + } + } + @Override public void setRingtonePlayer(IRingtonePlayer player) { mContext.enforceCallingOrSelfPermission(REMOTE_AUDIO_PLAYBACK, null); diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java index 55071ec043804..1ca0df47863ee 100644 --- a/media/java/android/media/AudioSystem.java +++ b/media/java/android/media/AudioSystem.java @@ -318,7 +318,8 @@ public class AudioSystem public static final int FORCE_BT_DESK_DOCK = 7; public static final int FORCE_ANALOG_DOCK = 8; public static final int FORCE_DIGITAL_DOCK = 9; - private static final int NUM_FORCE_CONFIG = 10; + public static final int FORCE_NO_BT_A2DP = 10; + private static final int NUM_FORCE_CONFIG = 11; public static final int FORCE_DEFAULT = FORCE_NONE; // usage for setForceUse, must match AudioSystem::force_use diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index 6753ad37a3776..7fbe28c5e6a03 100644 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -96,6 +96,10 @@ interface IAudioService { boolean isBluetoothScoOn(); + oneway void setBluetoothA2dpOn(boolean on); + + boolean isBluetoothA2dpOn(); + int requestAudioFocus(int mainStreamType, int durationHint, IBinder cb, IAudioFocusDispatcher l, String clientId, String callingPackageName);