Android6.0源码分析之蓝牙

前言

首先说一下在修改蓝牙时所涉及到的目录,Android6.0的源码目录文件稍微有一些改动

相关文件位于以下几个目录,

1,\Android\frameworks\base\core\Java\android\bluetooth,该目录下存放有诸如BluetoothAdapter,BluetoothDevice,等一些底层文件,



2,\android\frameworks\base\packages\SettingsLib\src\com\android\settingslib\bluetooth,存放的是一些蓝牙协议,服务相关的文件




这些文件一般也不需要改动,除非需要新增一些蓝牙的通信协议,一般修改蓝牙的以下目录的文件

3,Z:\R3\android\packages\apps\Settings\src\com\android\settings\bluetooth


有关蓝牙的可检测性设置,可检测时间设置,界面UI布局,蓝牙的开关等等,均在该目录下设置


对所有蓝牙涉及到的文件目录有所了解后开始分析,不论是分析Android4.4.2.源码还是Android6.0源码逻辑方法是类似的,有什么疑问可参考我的有关Android4.4.2的源码的分析


Chapter One

蓝牙fragment为BluetoothSettings.java,先按覆写的方法进行分析,大体上过一遍

1,onActivityCreated中

  1. mInitialScanStarted = (savedInstanceState != null);  

mInitialScanStarted为boolean型的值,是蓝牙扫描开始的开关,在扫描前会判断该Boolean的值,若为true,则表示不需要进行蓝牙扫描,若为false,则表示可以进行扫描

如果蓝牙界面没有被销毁(比如蓝牙界面锁屏解锁后),也就是说有状态记录的话该值为true,则蓝牙没必要进行扫描

  1. mInitiateDiscoverable = true;  

mInitiateDiscoverable顾名思义,蓝牙可检测性的开关,在对蓝牙的可检测性进行设置时首先判断该值,若为true,则设置为对附近所有设备可见

  1. mEmptyView = (TextView) getView().findViewById(android.R.id.empty);  
  2.         getListView().setEmptyView(mEmptyView);  
  3.         mEmptyView.setGravity(Gravity.START | Gravity.CENTER_VERTICAL);  

当界面没有任何preference时(比如蓝牙未开启状态下不显示任何preference)初始化一个textview,在屏幕上垂直居中,水平居左,比如在蓝牙未开启时会显示“要搜索可用设备,请打开蓝牙功能”等等

  1. final SettingsActivity activity = (SettingsActivity) getActivity();  
  2.         mSwitchBar = activity.getSwitchBar();  
  3.   
  4.         mBluetoothEnabler = new BluetoothEnabler(activity, mSwitchBar);  
  5.         mBluetoothEnabler.setupSwitchBar();  

这几句话值得重视一下,蓝牙界面有一个蓝牙开关,在Android4.4.2是无法进行滑动的,但是在Android6.0时开关和文字是分开呈现的,而且开关可滑动,类似ios的开关效果,多了一些美感。

在Android6.0中的开关是自定义的一个ToggleButton+TextView,具体自定义会在另一篇博客中交代,在获取到switchBar以后将其传给BluetoothEnabler,该类专门用于处理两件事,

一是根据蓝牙的当前状态对switch进行更新,

  1. void handleStateChanged(int state) {  
  2.         switch (state) {  
  3.             case BluetoothAdapter.STATE_TURNING_ON:  
  4.                 mSwitch.setEnabled(false);  
  5.                 break;  
  6.             case BluetoothAdapter.STATE_ON:  
  7.                 setChecked(true);  
  8.                 mSwitch.setEnabled(true);  
  9.                 updateSearchIndex(true);  
  10.                 mLocalAdapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE);  
  11.                 break;  
  12.             case BluetoothAdapter.STATE_TURNING_OFF:  
  13.                 mSwitch.setEnabled(false);  
  14.                 break;  
  15.             case BluetoothAdapter.STATE_OFF:  
  16.                 setChecked(false);  
  17.                 mSwitch.setEnabled(true);  
  18.                 updateSearchIndex(false);  
  19.                 break;  
  20.             default:  
  21.                 setChecked(false);  
  22.                 mSwitch.setEnabled(true);  
  23.                 updateSearchIndex(false);  
  24.         }  
  25.     }  

其实在这里可以看到在打开或者关闭蓝牙时,不仅是对switch进行设置操作,包括重新设置了蓝牙的可检测性,还有一个就是调用updateSearceIndex方法,用于更新数据的操作,在该方法中去更新跟蓝牙有关的一些数据,具体更新了什么数据,请稍待博客更新(不同于Android4.4.2)

二是,在switch开关滑动时对蓝牙的状态进行设

  1. public void onSwitchChanged(Switch switchView, boolean isChecked) {  
  2.         // Show toast message if Bluetooth is not allowed in airplane mode  
  3.         if (isChecked &&  
  4.                 !WirelessUtils.isRadioAllowed(mContext, Settings.Global.RADIO_BLUETOOTH)) {  
  5.             Toast.makeText(mContext, R.string.wifi_in_airplane_mode, Toast.LENGTH_SHORT).show();  
  6.             // Reset switch to off  
  7.             switchView.setChecked(false);  
  8.         }  
  9.   
  10.         MetricsLogger.action(mContext, MetricsLogger.ACTION_BLUETOOTH_TOGGLE, isChecked);  
  11.   
  12.         if (mLocalAdapter != null) {  
  13.          //在switch被check时去更新本地蓝牙状态(打开或者关闭)  
  14.            mLocalAdapter.setBluetoothEnabled(isChecked);  
  15.         }  
  16.        //设置switch不可点击  
  17.          mSwitch.setEnabled(false);  
  18.     }  

在蓝牙状态发生改变时会发送广播BluetoothAdapter.ACTION_STATE_CHANGED,接受到广播后,程序会调用handleStateChanged方法对switch进行更新。

接下来回过头来接着分析BluetoothSetitngs.java,分析到这里onActivityCreated方法已经分析完毕,接下来继续

2,onConfigurationChanged方法

通过在Androidmanifest清单配置文件的activity节点下配置android:configChanges属性,则在activity形状(可以是size或者orientation )发生改变时会执行该方法。该方法可以避免activity的重新加载

  1. if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {  

判断屏幕切换为横屏时的处理。布局title,switchbar,actionbar(返回键)


3,addPreferencesForActivity方法

  1. addPreferencesFromResource(R.xml.bluetooth_settings);  

加载界面布局,可以看出蓝牙UI的xml布局文件为Bluetooth_settings.xml;

  1. setHasOptionsMenu(true)  
允许创建菜单


4,onResume方法

  1. if (isUiRestricted()) {  
  2.             setDeviceListGroup(getPreferenceScreen());  
  3.             removeAllDevices();  
  4.             mEmptyView.setText(R.string.bluetooth_empty_list_user_restricted);  
  5.             return;  
  6.         }  

这句话是如果用户无权更改蓝牙设置时的处理,所有蓝牙相关的设置都无权更改

  1. getActivity().registerReceiver(mReceiver, mIntentFilter);  

注册广播,广播监听的action为BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED,当蓝牙名称发生改变时,会对显示本地蓝牙的preference信息进行更改,更改操作如下,信息显示在preference的summary
  1. if (mLocalAdapter.isEnabled() && mMyDevicePreference != null) {  
  2.                 mMyDevicePreference.setSummary(context.getResources().getString(  
  3.                             R.string.bluetooth_is_visible_message, mLocalAdapter.getName()));  
  4.             }  

-------------

  1. updateContent(mLocalAdapter.getBluetoothState());  

这句代码很关键,用来布局蓝牙界面,蓝牙布局的话可用设备和已配对设备基本都没什么改变,但是用来显示本机信息的preference显示在最后,而且只显示summary信息


5,onCreateOptionsMenu方法

添加菜单

  1. menu.add(Menu.NONE, MENU_ID_SCAN, 0, textId)//添加扫描菜单  
  2.          .setEnabled(bluetoothIsEnabled && !isDiscovering)  
  3.          .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);  
  4.  menu.add(Menu.NONE, MENU_ID_RENAME_DEVICE, 0, R.string.bluetooth_rename_device)  
  5.          .setEnabled(bluetoothIsEnabled)//重命名设备  
  6.          .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);  
  7.  menu.add(Menu.NONE, MENU_ID_SHOW_RECEIVED, 0, R.string.bluetooth_show_received_files)  
  8.         .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);//显示接收到的文件  

6,onDevicePreferenceClick方法

为preference添加点击事件,当点击已配对设备或者可用设备时首先停止扫描,然后判断是已配对设备还是可用设备,进而进行连接或者配对操作

  1. mLocalAdapter.stopScanning();  
  2.      super.onDevicePreferenceClick(btPreference);  


7,onBluetoothStateChanged方法

当蓝牙状态发生改变时-----turn/off,会触发该方法,这是因为该方法继承与父类DeviceListPreferenceFragment,在BluetoothEventManager中对蓝牙状态改变进行了监听,当蓝牙状态改变时会调用该方法


  1. if (BluetoothAdapter.STATE_ON == bluetoothState)  
  2.             mInitiateDiscoverable = true;  
  3.         updateContent(bluetoothState);  


蓝牙状态改变时首先判断是否处于开启状态,如果处于开启状态,则将可检测性的开关打开

只要状态发生改变,都会对蓝牙界面的设备的preference进行更新


8,onScanningStateChanged方法

调用机制:在BluetoothEventManager方法中对蓝牙的扫描状态进行监听,当扫描状态发生改变时会调用该方法

  1. if (getActivity() != null) {  
  2.            getActivity().invalidateOptionsMenu();  
  3.        }  

用来重新加载menu,这是因为menu上有个扫描按钮,需要根据扫描状态来更新扫描按钮的可点击性


9,onDeviceBondStateChanged方法

当配对状态发生改变时会调用该方法,清除设备列表,根据蓝牙的状态重新加载

展开阅读全文

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