diff options
-rw-r--r-- | media/java/android/media/AudioManager.java | 35 | ||||
-rw-r--r-- | media/java/android/media/AudioService.java | 48 | ||||
-rw-r--r-- | media/java/android/media/AudioSystem.java | 3 | ||||
-rw-r--r-- | 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 16cfa92..6c7c160 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 <var>true</var> to route A2DP audio to/from Bluetooth - * headset; <var>false</var> disable A2DP audio + * Allow or disallow use of Bluetooth A2DP for media. + * <p>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. + * <p>Requires Permission: + * {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS}. + * @param on set <var>true</var> to allow use of A2DP for media (default). + * <var>false</var> 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 da01c44..5e338ab 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 55071ec..1ca0df4 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 6753ad3..7fbe28c 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); |