Loading core/java/android/server/BluetoothA2dpService.java +37 −0 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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>(); Loading Loading @@ -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); } core/jni/android_server_BluetoothA2dpService.cpp +35 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -267,6 +299,7 @@ void onConnectSinkResult(DBusMessage *msg, void *user, void *n) { free(user); } #endif Loading @@ -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) { Loading Loading
core/java/android/server/BluetoothA2dpService.java +37 −0 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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>(); Loading Loading @@ -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); }
core/jni/android_server_BluetoothA2dpService.cpp +35 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -267,6 +299,7 @@ void onConnectSinkResult(DBusMessage *msg, void *user, void *n) { free(user); } #endif Loading @@ -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) { Loading