diff options
-rw-r--r-- | core/java/android/server/BluetoothA2dpService.java | 37 | ||||
-rw-r--r-- | core/jni/android_server_BluetoothA2dpService.cpp | 35 |
2 files changed, 72 insertions, 0 deletions
diff --git a/core/java/android/server/BluetoothA2dpService.java b/core/java/android/server/BluetoothA2dpService.java index 22bb43c..096ad39 100644 --- a/core/java/android/server/BluetoothA2dpService.java +++ b/core/java/android/server/BluetoothA2dpService.java @@ -121,10 +121,44 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { handleSinkStateChange(device, state, BluetoothA2dp.STATE_DISCONNECTED); } } + } else if (action.equals(AudioManager.VOLUME_CHANGED_ACTION)) { + int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1); + if (streamType == AudioManager.STREAM_MUSIC) { + BluetoothDevice sinks[] = getConnectedSinks(); + if (sinks.length != 0 && isPhoneDocked(sinks[0])) { + String address = sinks[0].getAddress(); + int newVolLevel = + intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, 0); + int oldVolLevel = + intent.getIntExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, 0); + String path = mBluetoothService.getObjectPathFromAddress(address); + if (newVolLevel > oldVolLevel) { + avrcpVolumeUpNative(path); + } else if (newVolLevel < oldVolLevel) { + avrcpVolumeDownNative(path); + } + } + } } } }; + + private boolean isPhoneDocked(BluetoothDevice device) { + // This works only because these broadcast intents are "sticky" + Intent i = mContext.registerReceiver(null, new IntentFilter(Intent.ACTION_DOCK_EVENT)); + if (i != null) { + int state = i.getIntExtra(Intent.EXTRA_DOCK_STATE, Intent.EXTRA_DOCK_STATE_UNDOCKED); + if (state != Intent.EXTRA_DOCK_STATE_UNDOCKED) { + BluetoothDevice dockDevice = i.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); + if (dockDevice != null && device.equals(dockDevice)) { + return true; + } + } + } + return false; + } + public BluetoothA2dpService(Context context, BluetoothService bluetoothService) { mContext = context; @@ -145,6 +179,7 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { mIntentFilter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED); mIntentFilter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED); mIntentFilter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED); + mIntentFilter.addAction(AudioManager.VOLUME_CHANGED_ACTION); mContext.registerReceiver(mReceiver, mIntentFilter); mAudioDevices = new HashMap<BluetoothDevice, Integer>(); @@ -551,4 +586,6 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { private synchronized native boolean suspendSinkNative(String path); private synchronized native boolean resumeSinkNative(String path); private synchronized native Object []getSinkPropertiesNative(String path); + private synchronized native boolean avrcpVolumeUpNative(String path); + private synchronized native boolean avrcpVolumeDownNative(String path); } diff --git a/core/jni/android_server_BluetoothA2dpService.cpp b/core/jni/android_server_BluetoothA2dpService.cpp index 4eab4b3..cf53a06 100644 --- a/core/jni/android_server_BluetoothA2dpService.cpp +++ b/core/jni/android_server_BluetoothA2dpService.cpp @@ -200,6 +200,38 @@ static jboolean resumeSinkNative(JNIEnv *env, jobject object, return JNI_FALSE; } +static jboolean avrcpVolumeUpNative(JNIEnv *env, jobject object, + jstring path) { +#ifdef HAVE_BLUETOOTH + LOGV(__FUNCTION__); + if (nat) { + const char *c_path = env->GetStringUTFChars(path, NULL); + bool ret = dbus_func_args_async(env, nat->conn, -1, NULL, NULL, nat, + c_path, "org.bluez.Control", "VolumeUp", + DBUS_TYPE_INVALID); + env->ReleaseStringUTFChars(path, c_path); + return ret ? JNI_TRUE : JNI_FALSE; + } +#endif + return JNI_FALSE; +} + +static jboolean avrcpVolumeDownNative(JNIEnv *env, jobject object, + jstring path) { +#ifdef HAVE_BLUETOOTH + LOGV(__FUNCTION__); + if (nat) { + const char *c_path = env->GetStringUTFChars(path, NULL); + bool ret = dbus_func_args_async(env, nat->conn, -1, NULL, NULL, nat, + c_path, "org.bluez.Control", "VolumeDown", + DBUS_TYPE_INVALID); + env->ReleaseStringUTFChars(path, c_path); + return ret ? JNI_TRUE : JNI_FALSE; + } +#endif + return JNI_FALSE; +} + #ifdef HAVE_BLUETOOTH DBusHandlerResult a2dp_event_filter(DBusMessage *msg, JNIEnv *env) { DBusError err; @@ -267,6 +299,7 @@ void onConnectSinkResult(DBusMessage *msg, void *user, void *n) { free(user); } + #endif @@ -281,6 +314,8 @@ static JNINativeMethod sMethods[] = { {"resumeSinkNative", "(Ljava/lang/String;)Z", (void*)resumeSinkNative}, {"getSinkPropertiesNative", "(Ljava/lang/String;)[Ljava/lang/Object;", (void *)getSinkPropertiesNative}, + {"avrcpVolumeUpNative", "(Ljava/lang/String;)Z", (void*)avrcpVolumeUpNative}, + {"avrcpVolumeDownNative", "(Ljava/lang/String;)Z", (void*)avrcpVolumeDownNative}, }; int register_android_server_BluetoothA2dpService(JNIEnv *env) { |