前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android6.0源码分析之蓝牙

Android6.0源码分析之蓝牙

作者头像
fanfan
发布2022-05-07 15:01:30
9030
发布2022-05-07 15:01:30
举报
文章被收录于专栏:编程思想之路编程思想之路

前言

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

代码语言:javascript
复制
 mInitialScanStarted = (savedInstanceState != null);

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

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

代码语言:javascript
复制
mInitiateDiscoverable = true;

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

代码语言:javascript
复制
mEmptyView = (TextView) getView().findViewById(android.R.id.empty);
        getListView().setEmptyView(mEmptyView);
        mEmptyView.setGravity(Gravity.START | Gravity.CENTER_VERTICAL);

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

代码语言:javascript
复制
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进行更新,

代码语言:javascript
复制
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开关滑动时对蓝牙的状态进行设

代码语言:javascript
复制
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的重新加载

代码语言:javascript
复制
 if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {

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

3,addPreferencesForActivity方法

代码语言:javascript
复制
addPreferencesFromResource(R.xml.bluetooth_settings);

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

代码语言:javascript
复制
setHasOptionsMenu(true)

允许创建菜单

4,onResume方法

代码语言:javascript
复制
if (isUiRestricted()) {
            setDeviceListGroup(getPreferenceScreen());
            removeAllDevices();
            mEmptyView.setText(R.string.bluetooth_empty_list_user_restricted);
            return;
        }

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

代码语言:javascript
复制
getActivity().registerReceiver(mReceiver, mIntentFilter);

注册广播,广播监听的action为BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED,当蓝牙名称发生改变时,会对显示本地蓝牙的preference信息进行更改,更改操作如下,信息显示在preference的summary

代码语言:javascript
复制
if (mLocalAdapter.isEnabled() && mMyDevicePreference != null) {
                mMyDevicePreference.setSummary(context.getResources().getString(
                            R.string.bluetooth_is_visible_message, mLocalAdapter.getName()));
            }
代码语言:javascript
复制
updateContent(mLocalAdapter.getBluetoothState());

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

5,onCreateOptionsMenu方法

添加菜单

代码语言:javascript
复制
       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添加点击事件,当点击已配对设备或者可用设备时首先停止扫描,然后判断是已配对设备还是可用设备,进而进行连接或者配对操作

代码语言:javascript
复制
   mLocalAdapter.stopScanning();
        super.onDevicePreferenceClick(btPreference);

7,onBluetoothStateChanged方法

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

代码语言:javascript
复制
if (BluetoothAdapter.STATE_ON == bluetoothState)
            mInitiateDiscoverable = true;
        updateContent(bluetoothState);

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

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

8,onScanningStateChanged方法

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

代码语言:javascript
复制
 if (getActivity() != null) {
            getActivity().invalidateOptionsMenu();
        }

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

9,onDeviceBondStateChanged方法

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

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016-06-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档