Android6.0源码分析之蓝牙

xiaoxiao2021-02-28  78

前言

首先说一下在修改蓝牙时所涉及到的目录,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中

[java] view plain copy mInitialScanStarted = (savedInstanceState != null);  

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

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

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

[java] view plain copy mEmptyView = (TextView) getView().findViewById(android.R.id.empty);          getListView().setEmptyView(mEmptyView);          mEmptyView.setGravity(Gravity.START | Gravity.CENTER_VERTICAL);   当界面没有任何preference时(比如蓝牙未开启状态下不显示任何preference)初始化一个textview,在屏幕上垂直居中,水平居左,比如在蓝牙未开启时会显示“要搜索可用设备,请打开蓝牙功能”等等

[java] view plain copy final SettingsActivity activity = (SettingsActivity) getActivity();          mSwitchBar = activity.getSwitchBar();            mBluetoothEnabler = new BluetoothEnabler(activity, mSwitchBar);          mBluetoothEnabler.setupSwitchBar();   这几句话值得重视一下,蓝牙界面有一个蓝牙开关,在Android4.4.2是无法进行滑动的,但是在Android6.0时开关和文字是分开呈现的,而且开关可滑动,类似ios的开关效果,多了一些美感。

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

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

[java] view plain copy void handleStateChanged(int state) {          switch (state) {              case BluetoothAdapter.STATE_TURNING_ON:                  mSwitch.setEnabled(false);                  break;              case BluetoothAdapter.STATE_ON:                  setChecked(true);                  mSwitch.setEnabled(true);                  updateSearchIndex(true);                  mLocalAdapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE);                  break;              case BluetoothAdapter.STATE_TURNING_OFF:                  mSwitch.setEnabled(false);                  break;              case BluetoothAdapter.STATE_OFF:                  setChecked(false);                  mSwitch.setEnabled(true);                  updateSearchIndex(false);                  break;              default:                  setChecked(false);                  mSwitch.setEnabled(true);                  updateSearchIndex(false);          }      }  

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

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

[java] view plain copy public void onSwitchChanged(Switch switchView, boolean isChecked) {          // Show toast message if Bluetooth is not allowed in airplane mode          if (isChecked &&                  !WirelessUtils.isRadioAllowed(mContext, Settings.Global.RADIO_BLUETOOTH)) {              Toast.makeText(mContext, R.string.wifi_in_airplane_mode, Toast.LENGTH_SHORT).show();              // Reset switch to off              switchView.setChecked(false);          }            MetricsLogger.action(mContext, MetricsLogger.ACTION_BLUETOOTH_TOGGLE, isChecked);            if (mLocalAdapter != null) {           //在switch被check时去更新本地蓝牙状态(打开或者关闭)             mLocalAdapter.setBluetoothEnabled(isChecked);          }         //设置switch不可点击           mSwitch.setEnabled(false);      }   在蓝牙状态发生改变时会发送广播BluetoothAdapter.ACTION_STATE_CHANGED,接受到广播后,程序会调用handleStateChanged方法对switch进行更新。

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

2,onConfigurationChanged方法

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

[java] view plain copy if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {   判断屏幕切换为横屏时的处理。布局title,switchbar,actionbar(返回键)

3,addPreferencesForActivity方法

[java] view plain copy addPreferencesFromResource(R.xml.bluetooth_settings);   加载界面布局,可以看出蓝牙UI的xml布局文件为Bluetooth_settings.xml;

[java] view plain copy setHasOptionsMenu(true)   允许创建菜单

4,onResume方法

[java] view plain copy if (isUiRestricted()) {              setDeviceListGroup(getPreferenceScreen());              removeAllDevices();              mEmptyView.setText(R.string.bluetooth_empty_list_user_restricted);              return;          }   这句话是如果用户无权更改蓝牙设置时的处理,所有蓝牙相关的设置都无权更改

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

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

[java] view plain copy updateContent(mLocalAdapter.getBluetoothState());   这句代码很关键,用来布局蓝牙界面,蓝牙布局的话可用设备和已配对设备基本都没什么改变,但是用来显示本机信息的preference显示在最后,而且只显示summary信息

5,onCreateOptionsMenu方法

添加菜单

[java] view plain copy menu.add(Menu.NONE, MENU_ID_SCAN, 0, textId)//添加扫描菜单           .setEnabled(bluetoothIsEnabled && !isDiscovering)           .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);   menu.add(Menu.NONE, MENU_ID_RENAME_DEVICE, 0, R.string.bluetooth_rename_device)           .setEnabled(bluetoothIsEnabled)//重命名设备           .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);   menu.add(Menu.NONE, MENU_ID_SHOW_RECEIVED, 0, R.string.bluetooth_show_received_files)          .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);//显示接收到的文件   6,onDevicePreferenceClick方法

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

[java] view plain copy mLocalAdapter.stopScanning();       super.onDevicePreferenceClick(btPreference);  

7,onBluetoothStateChanged方法

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

[java] view plain copy if (BluetoothAdapter.STATE_ON == bluetoothState)              mInitiateDiscoverable = true;          updateContent(bluetoothState);  

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

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

8,onScanningStateChanged方法

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

[java] view plain copy if (getActivity() != null) {             getActivity().invalidateOptionsMenu();         }   用来重新加载menu,这是因为menu上有个扫描按钮,需要根据扫描状态来更新扫描按钮的可点击性

9,onDeviceBondStateChanged方法

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

转载请注明原文地址: https://www.6miu.com/read-43007.html

最新回复(0)