diff options
-rw-r--r-- | core/java/android/bluetooth/BluetoothA2dp.java | 60 | ||||
-rw-r--r-- | core/java/android/bluetooth/IBluetoothA2dp.aidl | 3 | ||||
-rw-r--r-- | media/java/android/media/AudioManager.java | 29 | ||||
-rw-r--r-- | media/java/android/media/AudioService.java | 107 | ||||
-rw-r--r-- | media/java/android/media/IAudioService.aidl | 4 |
5 files changed, 184 insertions, 19 deletions
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java index d7d8cdb..e7e4a0f 100644 --- a/core/java/android/bluetooth/BluetoothA2dp.java +++ b/core/java/android/bluetooth/BluetoothA2dp.java @@ -388,6 +388,66 @@ public final class BluetoothA2dp implements BluetoothProfile { } /** + * Checks if Avrcp device supports the absolute volume feature. + * + * @return true if device supports absolute volume + * @hide + */ + public boolean isAvrcpAbsoluteVolumeSupported() { + if (DBG) Log.d(TAG, "isAvrcpAbsoluteVolumeSupported"); + if (mService != null && isEnabled()) { + try { + return mService.isAvrcpAbsoluteVolumeSupported(); + } catch (RemoteException e) { + Log.e(TAG, "Error talking to BT service in isAvrcpAbsoluteVolumeSupported()", e); + return false; + } + } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + return false; + } + + /** + * Tells remote device to adjust volume. Only if absolute volume is supported. + * + * @param direction 1 to increase volume, or -1 to decrease volume + * @hide + */ + public void adjustAvrcpAbsoluteVolume(int direction) { + if (DBG) Log.d(TAG, "adjustAvrcpAbsoluteVolume"); + if (mService != null && isEnabled()) { + try { + mService.adjustAvrcpAbsoluteVolume(direction); + return; + } catch (RemoteException e) { + Log.e(TAG, "Error talking to BT service in adjustAvrcpAbsoluteVolume()", e); + return; + } + } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + } + + /** + * Tells remote device to set an absolute volume. Only if absolute volume is supported + * + * @param volume Absolute volume to be set on AVRCP side + * @hide + */ + public void setAvrcpAbsoluteVolume(int volume) { + if (DBG) Log.d(TAG, "setAvrcpAbsoluteVolume"); + if (mService != null && isEnabled()) { + try { + mService.setAvrcpAbsoluteVolume(volume); + return; + } catch (RemoteException e) { + Log.e(TAG, "Error talking to BT service in setAvrcpAbsoluteVolume()", e); + return; + } + } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + } + + /** * Check if A2DP profile is streaming music. * * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. diff --git a/core/java/android/bluetooth/IBluetoothA2dp.aidl b/core/java/android/bluetooth/IBluetoothA2dp.aidl index 1f10998..26ff9e2 100644 --- a/core/java/android/bluetooth/IBluetoothA2dp.aidl +++ b/core/java/android/bluetooth/IBluetoothA2dp.aidl @@ -32,5 +32,8 @@ interface IBluetoothA2dp { int getConnectionState(in BluetoothDevice device); boolean setPriority(in BluetoothDevice device, int priority); int getPriority(in BluetoothDevice device); + boolean isAvrcpAbsoluteVolumeSupported(); + oneway void adjustAvrcpAbsoluteVolume(int direction); + oneway void setAvrcpAbsoluteVolume(int volume); boolean isA2dpPlaying(in BluetoothDevice device); } diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index 14cdbb7..ef02cfd 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -2387,6 +2387,35 @@ public class AudioManager { } } + /** + * @hide + * Notifies AudioService that it is connected to an A2DP device that supports absolute volume, + * so that AudioService can send volume change events to the A2DP device, rather than handling + * them. + */ + public void avrcpSupportsAbsoluteVolume(String address, boolean support) { + IAudioService service = getService(); + try { + service.avrcpSupportsAbsoluteVolume(address, support); + } catch (RemoteException e) { + Log.e(TAG, "Dead object in avrcpSupportsAbsoluteVolume", e); + } + } + + /** + * @hide + * Notifies AudioService of the volume set on the A2DP device as a callback, so AudioService + * is able to update the UI. + */ + public void avrcpUpdateVolume(int oldVolume, int volume) { + IAudioService service = getService(); + try { + service.avrcpUpdateVolume(oldVolume, volume); + } catch (RemoteException e) { + Log.e(TAG, "Dead object in avrcpUpdateVolume", e); + } + } + /** * {@hide} */ diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java index 290866e..470c571 100644 --- a/media/java/android/media/AudioService.java +++ b/media/java/android/media/AudioService.java @@ -460,6 +460,12 @@ public class AudioService extends IAudioService.Stub { private final MediaFocusControl mMediaFocusControl; + // Reference to BluetoothA2dp to query for AbsoluteVolume. + private BluetoothA2dp mA2dp; + private final Object mA2dpAvrcpLock = new Object(); + // If absolute volume is supported in AVRCP device + private boolean mAvrcpAbsVolSupported = false; + /////////////////////////////////////////////////////////////////////////// // Construction /////////////////////////////////////////////////////////////////////////// @@ -901,6 +907,15 @@ public class AudioService extends IAudioService.Stub { int oldIndex = mStreamStates[streamType].getIndex(device); if (adjustVolume && (direction != AudioManager.ADJUST_SAME)) { + // Check if volume update should be send to AVRCP + synchronized (mA2dpAvrcpLock) { + if (mA2dp != null && mAvrcpAbsVolSupported) { + mA2dp.adjustAvrcpAbsoluteVolume(direction); + return; + // No need to send volume update, because we will update the volume with a + // callback from Avrcp. + } + } if ((direction == AudioManager.ADJUST_RAISE) && !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) { Log.e(TAG, "adjustStreamVolume() safe volume index = "+oldIndex); @@ -998,6 +1013,15 @@ public class AudioService extends IAudioService.Stub { index = rescaleIndex(index * 10, streamType, streamTypeAlias); + synchronized (mA2dpAvrcpLock) { + if (mA2dp != null && mAvrcpAbsVolSupported) { + mA2dp.setAvrcpAbsoluteVolume(index); + return; + // No need to send volume update, because we will update the volume with a + // callback from Avrcp. + } + } + flags &= ~AudioManager.FLAG_FIXED_VOLUME; if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) && ((device & mFixedVolumeDevices) != 0)) { @@ -2268,21 +2292,23 @@ public class AudioService extends IAudioService.Stub { List<BluetoothDevice> deviceList; switch(profile) { case BluetoothProfile.A2DP: - BluetoothA2dp a2dp = (BluetoothA2dp) proxy; - deviceList = a2dp.getConnectedDevices(); - if (deviceList.size() > 0) { - btDevice = deviceList.get(0); - synchronized (mConnectedDevices) { - int state = a2dp.getConnectionState(btDevice); - int delay = checkSendBecomingNoisyIntent( - AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, - (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0); - queueMsgUnderWakeLock(mAudioHandler, - MSG_SET_A2DP_CONNECTION_STATE, - state, - 0, - btDevice, - delay); + synchronized (mA2dpAvrcpLock) { + mA2dp = (BluetoothA2dp) proxy; + deviceList = mA2dp.getConnectedDevices(); + if (deviceList.size() > 0) { + btDevice = deviceList.get(0); + synchronized (mConnectedDevices) { + int state = mA2dp.getConnectionState(btDevice); + int delay = checkSendBecomingNoisyIntent( + AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, + (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0); + queueMsgUnderWakeLock(mAudioHandler, + MSG_SET_A2DP_CONNECTION_STATE, + state, + 0, + btDevice, + delay); + } } } break; @@ -2344,10 +2370,13 @@ public class AudioService extends IAudioService.Stub { public void onServiceDisconnected(int profile) { switch(profile) { case BluetoothProfile.A2DP: - synchronized (mConnectedDevices) { - if (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)) { - makeA2dpDeviceUnavailableNow( - mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)); + synchronized (mA2dpAvrcpLock) { + mA2dp = null; + synchronized (mConnectedDevices) { + if (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)) { + makeA2dpDeviceUnavailableNow( + mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)); + } } } break; @@ -3697,6 +3726,7 @@ public class AudioService extends IAudioService.Stub { private void onSetA2dpConnectionState(BluetoothDevice btDevice, int state) { + if (DEBUG_VOL) Log.d(TAG, "onSetA2dpConnectionState btDevice="+btDevice+" state="+state); if (btDevice == null) { return; } @@ -3704,6 +3734,20 @@ public class AudioService extends IAudioService.Stub { if (!BluetoothAdapter.checkBluetoothAddress(address)) { address = ""; } + + // Disable absolute volume, if device is disconnected + synchronized (mA2dpAvrcpLock) { + if (state == BluetoothProfile.STATE_DISCONNECTED && mAvrcpAbsVolSupported) { + mAvrcpAbsVolSupported = false; + sendMsg(mAudioHandler, + MSG_SET_DEVICE_VOLUME, + SENDMSG_QUEUE, + getDeviceForStream(AudioSystem.STREAM_MUSIC), + 0, + mStreamStates[AudioSystem.STREAM_MUSIC], + 0); + } + } synchronized (mConnectedDevices) { boolean isConnected = (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) && @@ -3754,6 +3798,31 @@ public class AudioService extends IAudioService.Stub { } } + public void avrcpSupportsAbsoluteVolume(String address, boolean support) { + // address is not used for now, but may be used when multiple a2dp devices are supported + synchronized (mA2dpAvrcpLock) { + mAvrcpAbsVolSupported = support; + if (support) { + VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC]; + int device = getDeviceForStream(AudioSystem.STREAM_MUSIC); + streamState.setIndex(streamState.getMaxIndex(), device); + sendMsg(mAudioHandler, + MSG_SET_DEVICE_VOLUME, + SENDMSG_QUEUE, + device, + 0, + streamState, + 0); + } + } + } + + public void avrcpUpdateVolume(int oldVolume, int volume) { + mStreamStates[AudioSystem.STREAM_MUSIC]. + setIndex(volume, getDeviceForStream(AudioSystem.STREAM_MUSIC)); + sendVolumeUpdate(AudioSystem.STREAM_MUSIC, oldVolume, volume, AudioManager.FLAG_SHOW_UI); + } + private boolean handleDeviceConnection(boolean connected, int device, String params) { synchronized (mConnectedDevices) { boolean isConnected = (mConnectedDevices.containsKey(device) && diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index b4c8a04..903927b 100644 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -98,6 +98,10 @@ interface IAudioService { oneway void reloadAudioSettings(); + oneway void avrcpSupportsAbsoluteVolume(String address, boolean support); + + oneway void avrcpUpdateVolume(int oldVolume, int volume); + void setSpeakerphoneOn(boolean on); boolean isSpeakerphoneOn(); |