移植:
平台: rk3368 系统 android6.0
按网上的资料,http://blog.youkuaiyun.com/shichaog/article/details/52182987 。在 Android stdio 里移植,发现
import android.bluetooth.BluetoothAvrcpController;
import android.bluetooth.BluetoothAvrcp;
这两个 import 是找不到。查看源码,其实里面有的。网上查出原因,是因为用了 @hide 来隐藏,不暴露给app
于是想到在系统app 里尝试能否使用。
测试 在系统的源码里 package/app/Bluetooth 里的 src/com/android/bluetooth/a2dp/A2dpSinkStateMachine.java 加上
+import android.bluetooth.BluetoothAvrcpController;
+import android.bluetooth.BluetoothAvrcp;
编译,能够通过。证明系统app 是可以调用的。
于是在 A2dpSinkStateMachine.java 加了一个
+ mAvrcpController.sendPassThroughCmd(device, BluetoothAvrcp.PASSTHROUGH_ID_STOP, BluetoothAvrcp.PASSTHROUGH_STATE_PRESS);
+ mAvrcpController.sendPassThroughCmd(device, BluetoothAvrcp.PASSTHROUGH_ID_STOP, BluetoothAvrcp.PASSTHROUGH_STATE_RELEASE);
来暂停
那么问题来了,如何获取 mAvrcpController
看例子发现,需要一个 Listener
于是加了
+ private BluetoothProfile.ServiceListener mAvrcpServiceListener = new BluetoothProfile.ServiceListener(){
+ @Override
+ public void onServiceConnected(int profile, BluetoothProfile proxy) {
+ Log.d(TAG, "BT profile Service connected");
+ if (profile == BluetoothProfile.AVRCP_CONTROLLER){
+ Log.d(TAG, "AvrcpControllerService connected");
+
+ mAvrcpController = (BluetoothAvrcpController) proxy;
+// mAvrcpController.setCallback(new AvrcpControllerCallback());
+
+ Log.d(TAG, "Avrcp devices: ");
+ List<BluetoothDevice> devices = mAvrcpController.getConnectedDevices();
+ for (BluetoothDevice device : devices)
+ Log.d(TAG, " - " + device.getName() + " " + device.getAddress());
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(int profile) {
+ if (profile == BluetoothProfile.AVRCP_CONTROLLER) {
+ Log.d(TAG, "AvrcpControllerService disconnected");
+ //mAvrcpController.removeCallback();
+ mAvrcpController = null;
+ }
+ }
+ };
+
然而程序进不了 onServiceConnected ,mAvrcpController 为空
在framework 里加 log 发现 在 frameworks/base/core/java/android/bluetooth/BluetoothAdapter.java 里的 BluetoothAvrcpController avrcp = new BluetoothAvrcpController(context, listener);出了错。怀疑是 服务没有启动。
12-12 21:02:16.207 1700 1700 D BluetoothAdapter: wade getProfileProxy12
12-12 21:02:16.207 1700 1700 D BluetoothAdapter: wade new BluetoothAvrcpController
12-12 21:02:16.210 1700 1700 E BluetoothAvrcpController: Could not bind to Bluetooth AVRCP Controller Service with Intent { act=android.bluetooth.IBluetoothAvrcpController }
怎么启动 avrcp 的服务呢?没有想到很好的办法。比较以前有的一些补丁和源码。发现了问题。
--- a/packages/apps/Bluetooth/res/values/config.xml
+++ b/packages/apps/Bluetooth/res/values/config.xml
@@ -26,7 +26,7 @@
<bool name="pbap_include_photos_in_vcard">false</bool>
<bool name="pbap_use_profile_for_owner_vcard">true</bool>
<bool name="profile_supported_map">true</bool>
- <bool name="profile_supported_avrcp_controller">false</bool>
+ <bool name="profile_supported_avrcp_controller">true</bool>
<bool name="profile_supported_sap">false</bool>
在修改了这个之后,终于可以暂停手机端的音乐暂停了。
总结:
1. 编译要在源码里,编译系统app ,android stdio 用不了。
2. mAvrcpController 的获取需要加一个 BluetoothProfile.ServiceListener
3.系统本身要修改 config.xml 以打开 BluetoothAvrcpController 服务。
4. 只做到了一播放就暂停。关于场景的工作,(何时暂停,播放,或者按钮暂停播放没有做)
附所有的修改
app :
diff --git a/packages/apps/Bluetooth/res/values/config.xml b/packages/apps/Bluetooth/res/values/config.xml
index 0262064..57c8345 100644
--- a/packages/apps/Bluetooth/res/values/config.xml
+++ b/packages/apps/Bluetooth/res/values/config.xml
@@ -26,7 +26,7 @@
<bool name="pbap_include_photos_in_vcard">false</bool>
<bool name="pbap_use_profile_for_owner_vcard">true</bool>
<bool name="profile_supported_map">true</bool>
- <bool name="profile_supported_avrcp_controller">false</bool>
+ <bool name="profile_supported_avrcp_controller">true</bool>
<bool name="profile_supported_sap">false</bool>
<!-- If true, we will require location to be enabled on the device to
diff --git a/packages/apps/Bluetooth/src/com/android/bluetooth/a2dp/A2dpSinkStateMachine.java b/packages/apps/Bluetooth/src/com/android/bluetooth/a2dp/A2dpSinkStateMachine.
index ffe8931..a8bedda 100755
--- a/packages/apps/Bluetooth/src/com/android/bluetooth/a2dp/A2dpSinkStateMachine.java
+++ b/packages/apps/Bluetooth/src/com/android/bluetooth/a2dp/A2dpSinkStateMachine.java
@@ -35,6 +35,8 @@ import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothUuid;
import android.bluetooth.IBluetooth;
+import android.bluetooth.BluetoothAvrcpController;
+import android.bluetooth.BluetoothAvrcp;
import android.content.Context;
import android.media.AudioFormat;
import android.media.AudioManager;
@@ -106,6 +108,11 @@ final class A2dpSinkStateMachine extends StateMachine {
private final WakeLock mWakeLock;
private static final int MSG_CONNECTION_STATE_CHANGED = 0;
+ public static final int AVRC_ID_PAUSE = 0x46;
+ public static final int KEY_STATE_PRESSED = 0;
+ public static final int KEY_STATE_RELEASED = 1;
+ private BluetoothAvrcpController mAvrcpController;
+ private static final String TAG = "AVRCPa2dpsinktest";
// mCurrentDevice is the device connected before the state changes
// mTargetDevice is the device to be connected
@@ -145,6 +152,7 @@ final class A2dpSinkStateMachine extends StateMachine {
mService = svc;
mContext = context;
mAdapter = BluetoothAdapter.getDefaultAdapter();
+ mAdapter.getProfileProxy(context, mAvrcpServiceListener, BluetoothProfile.AVRCP_CONTROLLER);
initNative();
@@ -312,6 +320,9 @@ final class A2dpSinkStateMachine extends StateMachine {
log("Exit Disconnected: " + getCurrentMessage().what);
}
+
+
+
// in Disconnected state
private void processConnectionEvent(int state, BluetoothDevice device) {
switch (state) {
@@ -670,6 +681,8 @@ final class A2dpSinkStateMachine extends StateMachine {
mAudioManager.requestAudioFocus(mAudioFocusListener, AudioManager.STREAM_MUSIC,
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
audioPlay();
+ Log.d(TAG, "audioPlay now");
+ sendCommand(BluetoothAvrcp.PASSTHROUGH_ID_STOP);
break;
case AUDIO_STATE_REMOTE_SUSPEND:
logd("in remote suspend here do nothing");
@@ -687,6 +700,23 @@ final class A2dpSinkStateMachine extends StateMachine {
}
}
+ private void sendCommand(int keyCode){
+ if (mAvrcpController == null)
+ {
+ Log.d(TAG, "sendCommand mAvrcpController null");
+ return;
+ }
+
+
+ List<BluetoothDevice> devices = mAvrcpController.getConnectedDevices();
+ for (BluetoothDevice device : devices){
+ Log.d(TAG, "send command to device: "+ keyCode + device.getName() + " " + device.getAddress());
+ //<B8>÷<BD><B7><A8><CA><C7>Ҫ<U+05F7><D7>ٵ<C4><D6>ص<E3>֮<B6><FE>
+ mAvrcpController.sendPassThroughCmd(device, keyCode, BluetoothAvrcp.PASSTHROUGH_STATE_PRESS);
+ mAvrcpController.sendPassThroughCmd(device, keyCode, BluetoothAvrcp.PASSTHROUGH_STATE_RELEASE);
+ }
+ }
+
private void processAudioConfigEvent(BluetoothAudioConfig audioConfig, BluetoothDevice device) {
mAudioConfigs.put(device, audioConfig);
int lastSamprate = currentSamprate;
@@ -926,6 +956,34 @@ final class A2dpSinkStateMachine extends StateMachine {
}
};
+
+ private BluetoothProfile.ServiceListener mAvrcpServiceListener = new BluetoothProfile.ServiceListener(){
+ @Override
+ public void onServiceConnected(int profile, BluetoothProfile proxy) {
+ Log.d(TAG, "BT profile Service connected");
+ if (profile == BluetoothProfile.AVRCP_CONTROLLER){
+ Log.d(TAG, "AvrcpControllerService connected");
+
+ mAvrcpController = (BluetoothAvrcpController) proxy;
+// mAvrcpController.setCallback(new AvrcpControllerCallback());
+
+ Log.d(TAG, "Avrcp devices: ");
+ List<BluetoothDevice> devices = mAvrcpController.getConnectedDevices();
+ for (BluetoothDevice device : devices)
+ Log.d(TAG, " - " + device.getName() + " " + device.getAddress());
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(int profile) {
+ if (profile == BluetoothProfile.AVRCP_CONTROLLER) {
+ Log.d(TAG, "AvrcpControllerService disconnected");
+ //mAvrcpController.removeCallback();
+ mAvrcpController = null;
+ }
+ }
+ };
+
class RecordThread extends Thread{
@Override
public void run() {
diff --git a/packages/apps/Bluetooth/src/com/android/bluetooth/avrcp/AvrcpControllerService.java b/packages/apps/Bluetooth/src/com/android/bluetooth/avrcp/AvrcpControllerSe
index ed426ec..2bf0e30 100644
--- a/packages/apps/Bluetooth/src/com/android/bluetooth/avrcp/AvrcpControllerService.java
+++ b/packages/apps/Bluetooth/src/com/android/bluetooth/avrcp/AvrcpControllerService.java
@@ -40,7 +40,7 @@ import java.util.HashMap;
* @hide
*/
public class AvrcpControllerService extends ProfileService {
- private static final boolean DBG = false;
+ private static final boolean DBG = true;
private static final String TAG = "AvrcpControllerService";
private static final int MESSAGE_SEND_PASS_THROUGH_CMD = 1;
framework:
wade@SuperX:~/work/rk3368_618$ git diff frameworks
diff --git a/frameworks/base/core/java/android/bluetooth/BluetoothAdapter.java b/frameworks/base/core/java/android/bluetooth/BluetoothAdapter.java
index 1f3ff51..ba59f29 100644
--- a/frameworks/base/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/frameworks/base/core/java/android/bluetooth/BluetoothAdapter.java
@@ -1805,8 +1805,12 @@ public final class BluetoothAdapter {
*/
public boolean getProfileProxy(Context context, BluetoothProfile.ServiceListener listener,
int profile) {
- if (context == null || listener == null) return false;
-
+ if (context == null || listener == null)
+ {
+ Log.d(TAG, "wade getprofileproxy context or listenser is null");
+ return false;
+ }
+ Log.d(TAG, "wade getProfileProxy" + profile);
if (profile == BluetoothProfile.HEADSET) {
BluetoothHeadset headset = new BluetoothHeadset(context, listener);
return true;
@@ -1817,6 +1821,7 @@ public final class BluetoothAdapter {
BluetoothA2dpSink a2dpSink = new BluetoothA2dpSink(context, listener);
return true;
} else if (profile == BluetoothProfile.AVRCP_CONTROLLER) {
+ Log.d(TAG, "wade new BluetoothAvrcpController");
BluetoothAvrcpController avrcp = new BluetoothAvrcpController(context, listener);
return true;
} else if (profile == BluetoothProfile.INPUT_DEVICE) {
diff --git a/frameworks/base/core/java/android/bluetooth/BluetoothAvrcpController.java b/frameworks/base/core/java/android/bluetooth/BluetoothAvrcpController.java
index b53a8fc..425fba7 100644
--- a/frameworks/base/core/java/android/bluetooth/BluetoothAvrcpController.java
+++ b/frameworks/base/core/java/android/bluetooth/BluetoothAvrcpController.java
@@ -211,6 +211,7 @@ public final class BluetoothAvrcpController implements BluetoothProfile {
public void sendPassThroughCmd(BluetoothDevice device, int keyCode, int keyState) {
if (DBG) Log.d(TAG, "sendPassThroughCmd");
+ Log.d(TAG, "sendPassThroughCmd");
if (mService != null && isEnabled()) {
try {
mService.sendPassThroughCmd(device, keyCode, keyState);