Android 如何获取已连接的蓝牙设备

项目中有一个需求,就是获取已连接的蓝牙地址

[java]  view plain  copy
  1. private void getConnectBt() {  
  2.         LogUtil.i("getConnectBt");  
  3.   
  4.         int a2dp = _bluetoothAdapter.getProfileConnectionState(BluetoothProfile.A2DP);  
  5.         int headset = _bluetoothAdapter.getProfileConnectionState(BluetoothProfile.HEADSET);  
  6.         int health = _bluetoothAdapter.getProfileConnectionState(BluetoothProfile.HEALTH);  
  7.         int flag = -1;  
  8.         if (a2dp == BluetoothProfile.STATE_CONNECTED) {  
  9.             flag = a2dp;  
  10.         } else if (headset == BluetoothProfile.STATE_CONNECTED) {  
  11.             flag = headset;  
  12.         } else if (health == BluetoothProfile.STATE_CONNECTED) {  
  13.             flag = health;  
  14.         }  
  15.   
  16.         Log.d(TAG,"flag:"+flag);  
  17.         if (flag != -1) {  
  18.         _bluetoothAdapter.getProfileProxy(_context, new BluetoothProfile.ServiceListener() {  
  19.             @Override  
  20.             public void onServiceDisconnected(int profile) {  
  21.   
  22.             }  
  23.   
  24.             @Override  
  25.             public void onServiceConnected(int profile, BluetoothProfile proxy) {  
  26.                 List mDevices = proxy.getConnectedDevices();  
  27.                 if (mDevices != null && mDevices.size() > 0) {  
  28.                     for (BluetoothDevice device : mDevices) {  
  29.                         Log.d(TAG,device.getName() + "," + device.getAddress());  
  30.                     }  
  31.                 } else {  
  32.   
  33.                 }  
  34.             }  
  35.         }, flag);  
  36.   
  37.         }  
  38.     }  

从网上看到这段代码并没有作用,由于flag一直等于-1,所以一直返回BluetoothProfile.STATE_DISCONNECTED。也就是说
[java]  view plain  copy
  1. int a2dp = _bluetoothAdapter.getProfileConnectionState(BluetoothProfile.A2DP);  
  2. int headset = _bluetoothAdapter.getProfileConnectionState(BluetoothProfile.HEADSET);  
  3. int health = _bluetoothAdapter.getProfileConnectionState(BluetoothProfile.HEALTH);  
这三个方法都是返回的BluetoothProfile.STATE_DISCONNECTED

[java]  view plain  copy
  1. /** 
  2.  * Get the current connection state of a profile. 
  3.  * This function can be used to check whether the local Bluetooth adapter 
  4.  * is connected to any remote device for a specific profile. 
  5.  * Profile can be one of {@link BluetoothProfile#HEALTH}, {@link BluetoothProfile#HEADSET}, 
  6.  * {@link BluetoothProfile#A2DP}. 
  7.  * 
  8.  * 

    Requires {@link android.Manifest.permission#BLUETOOTH}. 

  9.  * 
  10.  * 

     Return value can be one of 

  11.  * {@link BluetoothProfile#STATE_DISCONNECTED}, 
  12.  * {@link BluetoothProfile#STATE_CONNECTING}, 
  13.  * {@link BluetoothProfile#STATE_CONNECTED}, 
  14.  * {@link BluetoothProfile#STATE_DISCONNECTING} 
  15.  */  
  16. public int getProfileConnectionState(int profile) {  
  17.     if (getState() != STATE_ON) return BluetoothProfile.STATE_DISCONNECTED;  
  18.     try {  
  19.         synchronized(mManagerCallback) {  
  20.             if (mService != nullreturn mService.getProfileConnectionState(profile);  
  21.         }  
  22.     } catch (RemoteException e) {  
  23.         Log.e(TAG, "getProfileConnectionState:", e);  
  24.     }  
  25.     return BluetoothProfile.STATE_DISCONNECTED;  
  26. }  

mService是IBluetooth接口对象

[java]  view plain  copy
  1. /** 
  2.  * Use {@link #getDefaultAdapter} to get the BluetoothAdapter instance. 
  3.  */  
  4. BluetoothAdapter(IBluetoothManager managerService) {  
  5.   
  6.     if (managerService == null) {  
  7.         throw new IllegalArgumentException("bluetooth manager service is null");  
  8.     }  
  9.     try {  
  10.         mService = managerService.registerAdapter(mManagerCallback);  
  11.     } catch (RemoteException e) {Log.e(TAG, "", e);}  
  12.     mManagerService = managerService;  
  13.     mLeScanClients = new HashMap();  
  14.     mHandler = new Handler(Looper.getMainLooper());  
  15. }  

[java]  view plain  copy
  1. public static synchronized BluetoothAdapter getDefaultAdapter() {  
  2.     if (sAdapter == null) {  
  3.         IBinder b = ServiceManager.getService(BLUETOOTH_MANAGER_SERVICE);  
  4.         if (b != null) {  
  5.             IBluetoothManager managerService = IBluetoothManager.Stub.asInterface(b);  
  6.             sAdapter = new BluetoothAdapter(managerService);  
  7.         } else {  
  8.             Log.e(TAG, "Bluetooth binder is null");  
  9.         }  
  10.     }  
  11.     return sAdapter;  
  12. }  

我们看到managerService是IBluetoothManager的Proxy,我们来找找Stub端在哪。
[java]  view plain  copy
  1. private static class AdapterServiceBinder extends IBluetooth.Stub  

[java]  view plain  copy
  1. class BluetoothManagerService extends IBluetoothManager.Stub  

[java]  view plain  copy
  1. public IBluetooth registerAdapter(IBluetoothManagerCallback callback){  
  2.     Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_ADAPTER);  
  3.     msg.obj = callback;  
  4.     mHandler.sendMessage(msg);  
  5.     synchronized(mConnection) {  
  6.         return mBluetooth;  
  7.     }  
  8. }  

我们继续看BluetoothAdapter的mService到底是什么

[java]  view plain  copy
  1. mBluetooth = IBluetooth.Stub.asInterface(service);  
[java]  view plain  copy
  1. private static class AdapterServiceBinder extends IBluetooth.Stub  

原来BluetoothAdapter的mService = mBluetooth = IBluetooth.Stub.asInterface(service),BluetoothManagerService只是个门面而已,真正干活的是IBluetooth.Stub也就是AdapterServiceBinder。我们回到最开始的问题,我们看AdapterService的getProfileConnectionState方法

[java]  view plain  copy
  1. int getProfileConnectionState(int profile) {  
  2.    enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");  
  3.   
  4.    return mAdapterProperties.getProfileConnectionState(profile);  
我们继续看AdapterProperties类

[java]  view plain  copy
  1. int getProfileConnectionState(int profile) {  
  2.     synchronized (mObject) {  
  3.         Pair p = mProfileConnectionState.get(profile);  
  4.         if (p != nullreturn p.first;  
  5.         return BluetoothProfile.STATE_DISCONNECTED;  
  6.     }  
  7. }  

mProfileConnectionState是干什么用的,在此之前我们先看看蓝牙的一些基本概念。

BluetoothProfile
描述Bluetooth Profile的接口。Bluetooth Profile是两个设备基于蓝牙通讯的无线接口描述。
(对Bluetooth Profile的详细解释,来自百度:为了更容易的保持Bluetooth设备之间的兼容,Bluetooth规范中定义了 Profile。Profile定义了设备如何实现一种连接或者应用,你可以把Profile理解为连接层或者应用层协议。 比如,如果一家公司希望它们的Bluetooth芯片支援所有的Bluetooth耳机,那么它只要支持HeadSet Profile即可,而无须考虑该芯片与其它Bluetooth设备的通讯与兼容性问题。如果你想购买Bluetooth产品,你应该了解你的应用需要哪 些Profile来完成,并且确保你购买的Bluetooth产品支持这些Profile。)
BluetoothHeadset
提供移动电话的Bluetooth耳机支持。包括Bluetooth耳机和Hands-Free (v1.5) profiles。
BluetoothA2dp
定义两个设备间如何通过Bluetooth连接进行高质量的音频传输。
A2DP(Advanced Audio Distribution Profile):高级音频传输模式。

mProfileConnectionState也就是管理各种profile连接情况的一个集合

很显然,我们最开始那段代码不起作用,是因为profile不对,我们来看profile都有哪些

[java]  view plain  copy
  1. /** 
  2.      * Headset and Handsfree profile 
  3.      */  
  4.     public static final int HEADSET = 1;  
  5.   
  6.     /** 
  7.      * A2DP profile. 
  8.      */  
  9.     public static final int A2DP = 2;  
  10.   
  11.     /** 
  12.      * Health Profile 
  13.      */  
  14.     public static final int HEALTH = 3;  
  15.   
  16.     /** 
  17.      * Input Device Profile 
  18.      * @hide 
  19.      */  
  20.     public static final int INPUT_DEVICE = 4;  
  21.   
  22.     /** 
  23.      * PAN Profile 
  24.      * @hide 
  25.      */  
  26.     public static final int PAN = 5;  
  27.   
  28.     /** 
  29.      * PBAP 
  30.      * @hide 
  31.      */  
  32.     public static final int PBAP = 6;  
  33.   
  34.     /** 
  35.      * GATT 
  36.      */  
  37.     static public final int GATT = 7;  
  38.   
  39.     /** 
  40.      * GATT_SERVER 
  41.      */  
  42.     static public final int GATT_SERVER = 8;  

我们列举了主要的几种,除了我们测试的HEADSET、A2DP、HEALTH外,还有GATT和GATT_SERVER,其实都是Hide。最开始的代码加上GATT和GATT_SERVER之后,依然没有结果。

实在没有办法了,我看到了BluetoothAdapter有一个hide方法直接调用了AdapterProperties的getConnectionState方法。

[java]  view plain  copy
  1. /** 
  2.  * @return the mConnectionState 
  3.  */  
  4. int getConnectionState() {  
  5.     synchronized (mObject) {  
  6.         return mConnectionState;  
  7.     }  
  8. }  

[java]  view plain  copy
  1. Class bluetoothAdapterClass = BluetoothAdapter.class;//得到BluetoothAdapter的Class对象  
  2.        try {//得到蓝牙状态的方法  
  3.            Method method = bluetoothAdapterClass.getDeclaredMethod("getConnectionState", (Class[]) null);  
  4.            //打开权限  
  5.            method.setAccessible(true);  
  6.            int state = (int) method.invoke(_bluetoothAdapter, (Object[]) null);  
  7.   
  8.            if(state == BluetoothAdapter.STATE_CONNECTED){  
  9.   
  10.                LogUtil.i("BluetoothAdapter.STATE_CONNECTED");  
  11.   
  12.                Set devices = _bluetoothAdapter.getBondedDevices();  
  13.                LogUtil.i("devices:"+devices.size());  
  14.   
  15.                for(BluetoothDevice device : devices){  
  16.   
  17.                    Method isConnectedMethod = BluetoothDevice.class.getDeclaredMethod("isConnected", (Class[]) null);  
  18.                    method.setAccessible(true);  
  19.                    boolean isConnected = (boolean) isConnectedMethod.invoke(device, (Object[]) null);  
  20.   
  21.                    if(isConnected){  
  22.                        LogUtil.i("connected:"+device.getAddress());  
  23.                        return device.getAddress();  
  24.                    }  
  25.   
  26.                }  
  27.   
  28.            }  
  29.   
  30.        } catch (Exception e) {  
  31.            e.printStackTrace();  
  32.        }  

利用反射获取了当前蓝牙连接的状态,根据getBondedDevices获取已绑定的蓝牙连接,然后遍历BluetoothDevice,同样利用反射的方法调用BluetoothDevice的isConnected方法。成功获取。


参考文章:

http://blog.csdn.net/mapeifan/article/details/50683956

你可能感兴趣的:(技术,Android,bluetooth,蓝牙已连接状态,蓝牙开发,蓝牙的源码分析)