Android 蓝牙开关

来源:互联网 发布:军训 知乎 编辑:程序博客网 时间:2024/05/22 14:32

转载请注明出处:http://blog.csdn.net/zrf1335348191/article/details/50995466

蓝牙相关代码已在另两篇文章中介绍,有需要的可以查看

Android4.42-Settings源码分析之蓝牙模块Bluetooth(上)

Android4.42-Setting源码分析之蓝牙模块Bluetooth(下)


ONE,SWITCH蓝牙开关

switch从创建到动作状态监听过程如下

  • 创建switch实例

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. Switch actionBarSwitch = new Switch(activity);  

  • 将实例添加到actionbar

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. activity.getActionBar().setCustomView(............);  


  • 通过构造方法将switch实例传递给BluetoothEnabler实例

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. mBluetoothEnabler = new BluetoothEnabler(activity, actionBarSwitch);  

  • 在fragment中调用添加菜单的方法

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. setHasOptionsMenu(true);  

  • 在onResume方法中对BluetoothEnabler的实例调用resume方法

以上一系列的代码都是在BluetoothSettings.Java中完成,接下来就是在BluetoothEnabler.java中进行处理

  • 判断蓝牙是否可用,不可用就把switch设置成不可点击
  • 根据本地蓝牙状态来更新switch状态
  • 注册过滤BluetoothAdapter.ACTION_STATE_CHANGE的广播,当蓝牙状态发生变化时更新switch状态
  • 为switch添加监听事件,更改本地蓝牙适配器,当本地蓝牙适配器发生改变后更新switch状态

总结,switch相关的逻辑实现就这些,在BluetoothSettings中创建switch实例,在BluetoothEnabler.java中对switch的状态监听及更新,查看代码不难发现BluetoothEnabler.java类中是专门对switch进行处理的类。


TWO,本地蓝牙相关

  • 创建本地蓝牙的preference

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. mMyDevicePreference = new Preference(getActivity());  

  • 显示到屏幕

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. preferenceScreen.addPreference(mMyDevicePreference);  

  • 构造BluetoothDiscoverableEnabler的实例对mMyDevicePreference的副标题summary进行显示更新

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. mDiscoverableEnabler = new BluetoothDiscoverableEnabler(getActivity(),  
  2.                                 mLocalAdapter, mMyDevicePreference);  
  3.                         mDiscoverableEnabler.resume();  

以上代码是在BluetoothSettings中完成,preference包括title--蓝牙名称、summary---蓝牙可检测性的更新

蓝牙名称--title的更新过程在BluetoothSettings.java中完成,过程如下

  • 获取到本机蓝牙名称

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. mMyDevicePreference.setTitle(mLocalAdapter.getName());  

  • 对蓝牙进行重命名操作时弹出对话框进行处理

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. new BluetoothNameDialogFragment().show(  
  2.                         getFragmentManager(), "rename device");  

在BluetoothNameDialogFragment.java中监听对话框中的编辑框,如果被编辑就修改本地蓝牙的名称,该类专用于为本机蓝牙重命名,

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. mLocalAdapter.setName();  

在当前的activity弹出对话框消失后程序不会执行onResume方法,所以在BluetoothSettings.java中注册广播

  • 当本地蓝牙名称改变后会发送BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED的广播,BluetoothSettings.java监听到广播后对mMyDevicePreference的title进行更新

蓝牙可检测性---summary的更新显示

对于summary的显示更新的操作在BluetoothDiscoverableEnabler.java中完成,该类专用于更新summary以及处理mMyDevicePreference的点击事件

  • 注册广播监听蓝牙扫描状态的改变,当蓝牙扫描状态发生改变时会发送BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE广播,对summary进行更新显示,调用第三步的方法
  • 为preference设置点击监听,更改扫描状态
  • 根据本地蓝牙的扫描状态来显示summary

在显示summary时有两种情况,

       i>,如果本地蓝牙既可以扫描又可以被检测到即处于SCAN_MODE_CONNECTABLE_DISCOVERABLE状态时,则根据可检测性时间的长短来显示,显示内容为:附近所有设备可以检测到+timeout

       ii>,如果是别的状态,则要根据是否已经有已配对的设备进行显示,显示为“已配对设备可见”或者是“对所有设备不可见”

既然说到了可检测性,直接说一说可检测时间,在程序启动时注册了广播BluetoothDiscoverableTimeoutReceiver,当可检测时间结束后就会将蓝牙的扫描状态设置为BluetoothAdapter.SCAN_MODE_CONNECTABLE,即取消对所有设备的可检测性

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. localBluetoothAdapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE);  
当设定了可检测性为固定的一段时间后则会设置一个闹钟,用于触发广播,当所规定的时间到达时会触发广播,将手机蓝牙的可检测性关闭,如果想要永久的可以被检测到,则只需讲闹钟取消掉,不再触发广播即可

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. Intent intent = new Intent(INTENT_DISCOVERABLE_TIMEOUT);  
  2.         intent.setClass(context, BluetoothDiscoverableTimeoutReceiver.class);  
  3.         PendingIntent pending = PendingIntent.getBroadcast(  
  4.             context, 0, intent, 0);  
  5.         AlarmManager alarmManager =  
  6.               (AlarmManager) context.getSystemService (Context.ALARM_SERVICE);  
  7.   
  8.         if (pending != null) {  
  9.             // Cancel any previous alarms that do the same thing.  
  10.             alarmManager.cancel(pending);  
  11.             Log.d(TAG, "setDiscoverableAlarm(): cancel prev alarm");  
  12.         }  
  13.         pending = PendingIntent.getBroadcast(  
  14.             context, 0, intent, 0);  
  15.   
  16.         alarmManager.set(AlarmManager.RTC_WAKEUP, alarmTime, pending);  

对于可检测性时间到达时对蓝牙可检测性的设置在BluetoothDiscoverableTimeoutReceiver.java中,该类为广播组件,专门用于开启或者关闭可检测性的闹钟计时、关闭可检测性。


THREE,设备列表相关

添加已配对设别列表

  • 创建PreferenceCategory类型可配对设备列表对象mPairedDevicesCategory

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. mPairedDevicesCategory = new PreferenceCategory(getActivity());  

  • 添加可配对设备列表mPairedDevicesCategory

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. addDeviceCategory(mPairedDevicesCategory,  
  2.                         R.string.bluetooth_preference_paired_devices,  
  3.                         BluetoothDeviceFilter.BONDED_DEVICE_FILTER);  


  • 调用如下方法将可配对设备列表传递给DeviceListPreferenceFragment进行管理

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. setDeviceListGroup(preferenceGroup);  

以上代码在BluetoothSettings中完成,接下来在DeviceListPreferenceFragment中对列表进行管理

  • 获取到设备缓存列表,该列表中存放已配对设设备和未配对设备,在程序安装成功后会通过BluetoothAdapter的getBondedDevices方法读取到已配对设备保存到缓存列表中
  • 为列表添加已配对的设备,所添加的对象为BluetoothDevicePreference构造的preference,也就是说单个设备的preference的管理在BluetoothDevicePreference中

添加附近可用设备列表

  • 点击扫描附近可用设备
  • 将附近可用设备列表显示到屏幕

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. getPreferenceScreen().addPreference(mAvailableDevicesCategory);  

  • 扫描到设备后缓存到缓存列表,然后显示到附近可用设备列表
  • 若附近可用设备列表为空,则移除

设备的点击事件在BluetoothDevicePreference中处理,设备状态不同则动作不同:如果是已配对设备则点击后就进行连接,如果是为配对的设备点击后进行配对,如果是已连接的设备点击后断开连接。



ONE,传统蓝牙

  • BluetoothAdapter:本地蓝牙设备适配器,用于管理蓝牙的开启/关闭、重命名、扫描、配对、连接
  • BluetoothClass:蓝牙设备类,用于描述蓝牙设备类型
  • BluetoothDevice:远程蓝牙设备类
  • BluetoothSocket:与tcpSocket类似,进行蓝牙连接
  • BluetoothServerSocket:与tcpServerSocket类似,等待连接


获取本地蓝牙适配器

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();  

打开/关闭本地蓝牙

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. adapter.enable();//打开蓝牙  
  2. adapter.disable();//关闭蓝牙  
  3. adapter.isEnabled();//蓝牙是否处于开启状态  
  4. adapter.getState();//获取本机蓝牙状态   

通过监听BluetoothAdapter.ACTION_STATE_CHANGED监听蓝牙状态的改变


蓝牙重命名/获取本机蓝牙名

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. mAdapter.setName(name);//本地蓝牙重命名  
  2. mAdapter.getName();//获取本机蓝牙名  

通过监听BluetoothAdpater.ACTION_LOCAL_NAME_CHANGED监听本机蓝牙名称的改变


蓝牙可检测性设置

有两种方案,

首先第一种实现,简单但对可检测时间有限制

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);  
  2.         //默认可检测时间为120秒,调用该方法最高可设置300秒  
  3.         intent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);  
  4.         startActivity(intent);  


第二种实现方案,就是Android源码中的实现方案,可以任意规定可检测时长,甚至永不超时均可(参考Android4.42源码)

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. /** 
  2. *mode有三种取值 
  3. *BluetoothAdapter.SCAN_MODE_CONNECTABLE:对已配对设备可见,具有扫描功能 
  4. *BluetoothAdapter.SCAN_MODE_NONE:对所有设备不可见,不具有扫描功能 
  5. *BluetoothAdapter.SCAN_MODE_CONNECTABLE_*DISCOVERABLE:对所有设备可见,具有扫描功能 
  6. *duration为扫描时长 
  7. */  
  8.   
  9. mAdapter.setScanMode(mode, duration);  
  10. //设置alarm,当timeout结束时就关闭蓝牙的可检测性  
  11. BluetoothDiscoverableTimeoutReceiver.setDiscoverableAlarm(mContext, endTimestamp);  
这是源码中的实现方案,但是BluetoothAdapter.setScanMode()没有办法去调用,只能利用反射

获取已配对设备列表

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. List<BluetoothDevice> list = (List<BluetoothDevice>) adapter.getBondedDevices();  

开启扫描/关闭扫描

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. adapter.startDiscovery();//开启蓝牙扫描功能  
  2. adapter.cancelDiscovery();//关闭蓝牙扫描功能  

在扫描到设备时系统会发送BluetoothDevice.ACTION_FOUND的广播,通过监听该广播可以获取到设备信息

获取到设备后调用如下方式进行连接

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. BluetoothSocket _BluetoothSocket = device.createInsecureRfcommSocketToServiceRecord(MY_UUID);  

获取到socket后可以获取到输入输出流,这里的uuid可以在网页的uuid生成器在线生成,remotedevice和本机蓝牙设备的uuid必须相同


TWO,BLE低功耗蓝牙

获取蓝牙适配器的步骤同上,扫描ble设备的方法如下:

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. //开启蓝牙扫描  
  2. mBluetoothAdapter.startLeScan(mLeScanCallback);  
  3. //结束蓝牙扫描  
  4. mBluetoothAdapter.stopLeScan(mLeScanCallback);  

其中mlLeScanCallback为BluetoothAdapter.LeScanCallback对象,

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. private BluetoothAdapter.LeScanCallback mLeScanCallback =  
  2.             new BluetoothAdapter.LeScanCallback() {  
  3.   
  4.         @Override  
  5.         public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {  
  6.                        。。。  
  7.                    //扫描到设备后回调  
  8. }  


扫描到设备后可以进行连接,方法如下

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. mBluetoothGatt = mBluetoothDevice.connectGatt(BluetoothCODAService.thisfalse, mGattCallback);  

其中mGattCallback为BluetoothGattCallback对象

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1.  private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {  
  2.         @Override  
  3.         public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {  
  4.   
  5.             if(newState == BluetoothProfile.STATE_CONNECTED){  
  6.             //连接成功回调  
  7.           
  8.             }else if(newState == BluetoothProfile.STATE_DISCONNECTED){  
  9.                //连接失败回调  
  10.                       }  
  11.           public void onServicesDiscovered(BluetoothGatt gatt, int status) {  
  12.                      
  13.             if (status == BluetoothGatt.GATT_SUCCESS) { // 0  
  14.                                          //搜索到服务回调  
  15.   
  16.       } else {  
  17.     //未搜索到服务回调  
  18.             }  
  19.         }  
  20.   
  21.         @Override  
  22.         // Result of a characteristic read operation  
  23.         public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {  
  24.             if (status == BluetoothGatt.GATT_SUCCESS) {  
  25.                 //接收到数据回调  
  26.             }  
  27.         }  
  28.   
  29.          @Override  
  30.          public void onCharacteristicWrite(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic, int status) {  
  31.           //发送数据回调  
  32.          }  
  33.       
  34.         @Override  
  35.         public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {  
  36.             
  37.         }  
  38.   
  39.         @Override  
  40.             public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor,  
  41.                                  int status) {  
  42.         }  
  43.   
  44.         @Override  
  45.         public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor,  
  46.                                       int status) {  
  47.         }      
  48.   
  49.         @Override  
  50.         public void onReliableWriteCompleted(BluetoothGatt gatt, int status) {  
  51.           
  52.            }  
  53.     };  
  54.   
  55.  }  
            

连接成功后如果要进行通信还必须搜索服务

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. mBluetoothGatt.discoverServices();  

搜索服务后会回调onServicesDiscovered方法。

至此,就可以进行读写数据了

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. //读数据  
  2. mBluetoothGatt.readCharacteristic(characteristic);  
  3. //写数据  
  4.  mBluetoothGatt.writeCharacteristic(characteristic,value);  

关于低功耗蓝牙的理论知识可以参考 Android蓝牙BLE低功耗相关简单总结
0 0
原创粉丝点击