Android实现主动连接蓝牙耳机

在Android程序中可以实现自动扫描蓝牙、配对蓝牙、建立数据通道。
蓝牙分不同类型,可以参考(http://gqdy365.iteye.com/admin/blogs/2229304)
可以入下面方法获取蓝牙设备支持的类型:

Java代码  收藏代码
  1. BluetoothDevice device;  
  2. Arrays.toString(device.getUuids());  



我的蓝牙音箱支持的类型有:

Java代码  收藏代码
  1. 0000111e-0000-1000-8000-00805f9b34fb:Handsfree  
  2. 0000110b-0000-1000-8000-00805f9b34fb:AudioSink  
  3. 0000110e-0000-1000-8000-00805f9b34fb:AVRemoteControl  
  4. 00001203-0000-1000-8000-00805f9b34fb:GenericFileTransfer  



这篇文字只讨论如何与蓝牙耳机(蓝牙音箱)连接。
蓝牙耳机一般都支持A2DP(蓝牙立体声,用于音乐播放)、HFP协议(通话),参考:http://gqdy365.iteye.com/admin/blogs/2231553
所以下面操作要同时操作A2DP和HFP,两个都连接成功,才算连接成功;

一、A2DP的操作可以分三步:

1、扫描蓝牙设备:
注册并监听广播:

Java代码  收藏代码
  1. BluetoothAdapter.ACTION_DISCOVERY_STARTED  
  2. BluetoothDevice.ACTION_FOUND  
  3. BluetoothAdapter.ACTION_DISCOVERY_FINISHED  


启动扫描:

Java代码  收藏代码
  1. BluetoothAdapter.getDefaultAdapter().startDiscovery();  



对扫描的结果按类型进行筛选,只保留我们需要的蓝牙耳机:

Java代码  收藏代码
  1.         if(device.getBluetoothClass().getDeviceClass() == BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET  
  2.                 || device.getBluetoothClass().getDeviceClass() == BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE){  
  3. //蓝牙耳机  
  4. }  



2、配对指定的蓝牙设备:
这个跟配对普通蓝牙一样,方法如下:

Java代码  收藏代码
  1. public static  boolean createBond(BluetoothDevice btDevice){  
  2.     boolean result = false;  
  3.     try{  
  4.         Method m = btDevice.getClass().getDeclaredMethod("createBond",new Class[]{});  
  5.         m.setAccessible(true);  
  6.         Boolean originalResult = (Boolean) m.invoke(btDevice);  
  7.         result = originalResult.booleanValue();  
  8.     }catch(Exception ex){  
  9.     }  
  10.     return result;  
  11. }  



等配对完成之后就是要建立数据连接;

3、建立数据连接:

if you SDK between 11 and 16.call a2dp.connectSink(btDevice) or a2dp.connect(btDevice)

Java代码  收藏代码
  1. private static IBluetoothA2dp getIBluetoothA2dp() {  
  2.     IBluetoothA2dp ibta = null;  
  3.   
  4.     try {  
  5.         final Class serviceManager = Class.forName("android.os.ServiceManager");  
  6.         final Method getService = serviceManager.getDeclaredMethod("getService", String.class);  
  7.         final IBinder iBinder = (IBinder) getService.invoke(null, "bluetooth_a2dp");  
  8.         final Class iBluetoothA2dp = Class.forName("android.bluetooth.IBluetoothA2dp");  
  9.         final Class[] declaredClasses = iBluetoothA2dp.getDeclaredClasses();  
  10.         final Class c = declaredClasses[0];  
  11.         final Method asInterface = c.getDeclaredMethod("asInterface", IBinder.class);  
  12.   
  13.         asInterface.setAccessible(true);  
  14.         ibta = (IBluetoothA2dp) asInterface.invoke(null, iBinder);  
  15.     } catch (final Exception e) {  
  16.         Log.e("Error " + e.getMessage());  
  17.     }  
  18.     return ibta;  
  19. }  


参考:http://stackoverflow.com/questions/8467178/working-around-a2dp-and-hfp-limitations-of-android-pre-honeycomb

如果API大于16需要用如下的方法:

Java代码  收藏代码
  1.     private void initA2dpService(){  
  2. //      Intent i = getExplicitIntent(mContext,new Intent(IBluetoothA2dp.class.getName()));//5.0以上系统需要显示intent  
  3. //详细参考http://blog.csdn.net/l2show/article/details/47421961  
  4.         Intent i = new Intent(IBluetoothA2dp.class.getName());  
  5.         boolean success = mContext.bindService(i, mConnection, Context.BIND_AUTO_CREATE);  
  6.         if (success) {  
  7.   
  8.         } else {  
  9.         }  
  10.     }  
  11.   
  12.     public ServiceConnection mConnection = new ServiceConnection() {  
  13.   
  14.         @Override  
  15.         public void onServiceConnected(ComponentName name, IBinder service) {  
  16.             try {  
  17.                 mA2dpService = IBluetoothA2dp.Stub.asInterface(service);  
  18.             } catch (Exception e) {  
  19.                 e.printStackTrace();  
  20.             }  
  21.         }  
  22.   
  23.         @Override  
  24.         public void onServiceDisconnected(ComponentName name) {  
  25.             // TODO Auto-generated method stub  
  26.   
  27.         }  
  28.   
  29.     };  
  30.       
  31.     public Intent getExplicitIntent(Context context, Intent implicitIntent) {  
  32.         // Retrieve all services that can match the given intent  
  33.         PackageManager pm = context.getPackageManager();  
  34.         List<ResolveInfo> resolveInfo = pm.queryIntentServices(implicitIntent, 0);  
  35.         // Make sure only one match was found  
  36.         if (resolveInfo == null || resolveInfo.size() != 1) {  
  37.             return null;  
  38.         }  
  39.         // Get component info and create ComponentName  
  40.         ResolveInfo serviceInfo = resolveInfo.get(0);  
  41.         String packageName = serviceInfo.serviceInfo.packageName;  
  42.         String className = serviceInfo.serviceInfo.name;  
  43.         ComponentName component = new ComponentName(packageName, className);  
  44.         // Create a new intent. Use the old one for extras and such reuse  
  45.         Intent explicitIntent = new Intent(implicitIntent);  
  46.         // Set the component to be explicit  
  47.         explicitIntent.setComponent(component);  
  48.         return explicitIntent;  
  49.     }  


建立连接:mA2dpService.connect(device);
断开连接:mA2dpService.disconnect(device);

参考:http://stackoverflow.com/questions/14705167/how-connect-paired-bluetooth-a2dp-device-on-android-4-2-using-reflection

http://blog.csdn.net/qs_csu/article/details/45114251

二、HFP操作:
下面只针对4.0及以上版本;
1、初始化:

Java代码  收藏代码
  1. private void initOrCloseBtCheck(boolean init){  
  2.     if(init){  
  3.         mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();  
  4.         mBluetoothAdapter.getProfileProxy(mContext, new ServiceListener() {  
  5.             public void onServiceConnected(int profile, BluetoothProfile proxy) {  
  6.                 if (profile == BluetoothProfile.HEADSET) {  
  7.                     mBluetoothHeadset = (BluetoothHeadset) proxy;  
  8.                 }  
  9.             }  
  10.   
  11.             public void onServiceDisconnected(int profile) {  
  12.                 if (profile == BluetoothProfile.HEADSET) {  
  13.                     mBluetoothHeadset = null;  
  14.                 }  
  15.             }  
  16.         },BluetoothProfile.HEADSET);  
  17.     }else{  
  18.         mBluetoothAdapter.closeProfileProxy(BluetoothProfile.HEADSET,mBluetoothHeadset);  
  19.     }  
  20. }  



建立连接:

Java代码  收藏代码
  1.          Method m = mBluetoothHeadset.getClass().getDeclaredMethod("connect",BluetoothDevice.class);    
  2. m.setAccessible(true);  
  3. //连接Headset  
  4. boolean successHeadset = (Boolean)m.invoke(mBluetoothHeadset, device);  



断开连接:

Java代码  收藏代码
  1.          Method m = mBluetoothHeadset.getClass().getDeclaredMethod("disconnect",BluetoothDevice.class);    
  2. m.setAccessible(true);  
  3. m.invoke(mBluetoothHeadset, device);  




三、状态判断:

蓝牙耳机连接成功:

Java代码  收藏代码
  1. mA2dpService.getConnectionState(device) == BluetoothA2dp.STATE_DISCONNECTED && mBluetoothHeadset.getConnectionState(device) == BluetoothProfile.STATE_DISCONNECTED  


断开成功:

Java代码  收藏代码
    1. (mA2dpService.getConnectionState(device) == BluetoothA2dp.STATE_CONNECTED || mA2dpService.getConnectionState(device) == BluetoothA2dp.STATE_PLAYING)  
    2.                                 && mBluetoothHeadset.getConnectionState(device) == BluetoothProfile.STATE_CONNECTED 
展开阅读全文

蓝牙耳机连接错误

10-10

蓝牙耳机与手机配对并连接好后会显示“已连接到手机和媒体音频”的提示信息,此时播放音乐和接听电话都可以从蓝牙耳机出来,接着手机重启后蓝牙耳机与手机自动配对只成功连接到媒体音频,显示"已连接到媒体音频",此时播放音乐可以从蓝牙耳机出音但接听电话是从receiver出音的。从log看是在android_bluetooth_headsetbase.cpp的waitForAsyncConnectNative()出错了。rnrn01-01 09:32:00.690 I/BT HSHFP( 202): waitForAsyncConnectNative function start connectAysncNativernrn01-01 09:32:00.690 I/BT HSHFP( 202): Created RFCOMM socket fd 71.rnrn01-01 09:32:00.690 I/BT HSHFP( 202): connectAsyncNative: connect to bt-headset channel=1 addr=00:0B:E4:A9:CC:CArnrn01-01 09:32:00.690 I/BT HSHFP( 202): async connect is in progress (Operation now in progress)rnrn01-01 09:32:00.770 I/BT HSHFP( 202): waitForAsyncConnectNative: select() result=2 timeout=500 set_read=1 set_write=1rnrn01-01 09:32:00.770 I/BT HSHFP( 202): waitForAsyncConnectNative: read() result=-1 read=0 error:Connection refused (111)rnrn01-01 09:32:00.770 E/BT HSHFP( 202): RFCOMM async connect() error: Connection refused (111), nr = -1rnrn01-01 09:32:00.770 I/BT HSHFP( 202): Trying to connect to rfcomm socket result=-111rnrn01-01 09:32:00.770 D/BT HSHFP( 202): RFCOMM connection attempt took 1173 msrnrn01-01 09:32:00.770 W/BT HSHFP( 202): headset.waitForAsyncConnect() error: -111rnrn01-01 09:32:00.770 D/BT HSHFP( 202): Rfcomm errorrnrnlog如上面所示,select()的返回结果就和期望的不一样了,code上有注释返回结果为1才是正确的,但这里的结果确实2,难道是fdset_read与fdset_write都被设置后的结果么,结果为1时只有fdset_write会被设置过。rn请问有谁碰上过这样的问题吗,是什么原因造成的呢,如何解决? 论坛

没有更多推荐了,返回首页