Settings源码分析之蓝牙(1)

Android  源码分析  2018年8月9日 pm8:41发布6年前 (2018)更新 91es.com站长
65 0 0


源码:Android 6.0

应用:Settings

目录:Settings\src\com\android\settings\bluetooth

 

上一回我们简单分析了Settings加载和启动过程(《Android 6.0 Settings源码简单分析》),现在我们来看看Settings中的一个小功能:蓝牙。

我们前面分析到,Settings界面上布局显示的内容是在 SettingsActivity.getDashboardCategories()中解析R.xml.dashboard_categories 内容的,然后在SettingsActivity.updateTilesList()中判断是否需要显示或影藏。(这部分内容在《Android 6.0 Settings源码简单分析》中的第5和第6索引中,有兴趣的可以看看)

这次我们重点看蓝牙,因此看看R.xml.dashboard_categories中对蓝牙的描述。

         ......
        <!-- Bluetooth -->
        <dashboard-tile
            android:id="@+id/bluetooth_settings"
            android:fragment="com.android.settings.bluetooth.BluetoothSettings"
            android:icon="@drawable/ic_settings_bluetooth"
            android:title="@string/bluetooth_settings_title" />
           ......

上面包含的信息有id,Fragment,icon和title,BluetoothSettings就是蓝牙的入口类。

既然知道了入口,那我们开始进入正题吧、

0、BluetoothSettings.java的继承关系

我们先看看BluetoothSettings的继承关系,先了解这些关系对我们往下分析很有帮助的。

public final class BluetoothSettings extends DeviceListPreferenceFragment implements Indexable {
   ......
}

public abstract class DeviceListPreferenceFragment extends
        RestrictedSettingsFragment implements BluetoothCallback {
    ......
}

public abstract class RestrictedSettingsFragment extends SettingsPreferenceFragment {
    ......
}

public abstract class SettingsPreferenceFragment extends InstrumentedPreferenceFragment
        implements DialogCreatable {
    ......
}

public abstract class InstrumentedPreferenceFragment extends PreferenceFragment {
   ......
}

public abstract class PreferenceFragment extends Fragment implements
        PreferenceManager.OnPreferenceTreeClickListener {
  ......
}

从上面可以了解到BluetoothSettings的祖祖祖祖父是Fragment,额,是不是很熟悉啦。关于Fragment的简单介绍可以看看我前几天写(摘抄)的《Fragment生命周期的详情》,这里就不再重复。

恩恩,有了前面的Fragment的生命周期知识,我们先看BluetoothSettings的生命周期,首先看的是onCreate(),额,神马,竟然没有实现onCreate(),好吧,那我们只好找他老爸了。

PS:后面分析是根据Fragment的生命周期流程去分析的,这是蓝牙初始化界面的流程。

1、DeviceListPreferenceFragment.onCreate()

//DeviceListPreferenceFragment.java
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        初始化LocalBluetoothManager
        mLocalManager = Utils.getLocalBtManager(getActivity());
        if (mLocalManager == null) {
            看看是否支持蓝牙,如果不支持,Settings中的蓝牙选项是打不开的
            Log.e(TAG, "Bluetooth is not supported on this device");
            return;
        }
        mLocalAdapter = mLocalManager.getBluetoothAdapter();
        1.1 、这是个抽象方法,具体实现在其子类BluetoothSettings
        addPreferencesForActivity();
        mDeviceListGroup = (PreferenceCategory) findPreference(KEY_BT_DEVICE_LIST);
    }

addPreferencesForActivity是个抽象方法,具体实现是在BluetoothSettings中。只有该设备支持蓝牙才会继续执行,要不然会点不进入的。

1.1、BluetoothSettings.addPreferencesForActivity()

其实这里没有做啥工作,就是添加布局和设置有Menu栏。

    @Override
    void addPreferencesForActivity() {
        addPreferencesFromResource(R.xml.bluetooth_settings);
        setHasOptionsMenu(true);
    }

而bluetooth_settings.xml里面啥都没放就一个PreferenceScreen(对于PreferenceScreen使用,后续再说)

<PreferenceScreen
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:title="@string/bluetooth_settings" >

</PreferenceScreen>

2、BluetoothSettings.onActivityCreated()

   // BluetoothSettings.java
    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        ......
        一开始进入显示空的界面(蓝牙没有开启时的界面)
        mEmptyView = (TextView) getView().findViewById(android.R.id.empty);
        getListView().setEmptyView(mEmptyView);
        mEmptyView.setGravity(Gravity.START | Gravity.CENTER_VERTICAL);
        初始化mSwitchBar蓝牙开关键
        final SettingsActivity activity = (SettingsActivity) getActivity();
        mSwitchBar = activity.getSwitchBar();
        2.1 初始化mBluetoothEnabler
        mBluetoothEnabler = new BluetoothEnabler(activity, mSwitchBar);
        显示SwitchBar开关
        mBluetoothEnabler.setupSwitchBar();
    }

2.1 初始化mBluetoothEnabler

    //BluetoothEnabler.java
     public BluetoothEnabler(Context context, SwitchBar switchBar) {
        ......
        初始化LocalBluetoothManager
        LocalBluetoothManager manager = Utils.getLocalBtManager(context);
        if (manager == null) {
            如果不支持,就把Switchbar设置为不能使用// Bluetooth is not supported
            mLocalAdapter = null;
            mSwitch.setEnabled(false);
        } else {
            mLocalAdapter = manager.getBluetoothAdapter();
        }
        mIntentFilter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
    }

4、BluetoothSettings.onResume()

    //BluetoothSettings.java
    @Override
    public void onResume() {
        // resume BluetoothEnabler before calling super.onResume() so we don't get
        // any onDeviceAdded() callbacks before setting up view in updateContent()
        if (mBluetoothEnabler != null) {
            4.1 更新蓝牙开关的状态和注册广播
            mBluetoothEnabler.resume(getActivity());
        }
        ......
        检测是否被限制操作蓝牙
        if (isUiRestricted()) {
            setDeviceListGroup(getPreferenceScreen());
            removeAllDevices();
            mEmptyView.setText(R.string.bluetooth_empty_list_user_restricted);
            return;
        }
        注册蓝牙名字改变广播(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED)
        getActivity().registerReceiver(mReceiver, mIntentFilter);
        if (mLocalAdapter != null) {
            4.3、更新蓝牙状态
            updateContent(mLocalAdapter.getBluetoothState());
        }
    }
4.1、mBluetoothEnabler.resume()
    //BluetoothEnabler.java
    public void resume(Context context) {
        if (mLocalAdapter == null) {
            mSwitch.setEnabled(false);
            return;
        }
        ......
        // Bluetooth state is not sticky, so set it manually
        更新蓝牙开关状态(STATE_TURNING_ON、STATE_ON、STATE_TURNING_OFF、STATE_OFF)
        handleStateChanged(mLocalAdapter.getBluetoothState());
        4.2 监听Switch bar 开关的改变事件
        mSwitchBar.addOnSwitchChangeListener(this);
        注册蓝牙状态改变广播(BluetoothAdapter.ACTION_STATE_CHANGED)
        mContext.registerReceiver(mReceiver, mIntentFilter);
        mValidListener = true;
    }
4.2、  监听Switch bar 开关的改变事件
    @Override
    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) {
            mLocalAdapter.setBluetoothEnabled(isChecked);
        }
        正在更新状态时设置不能点击
        mSwitch.setEnabled(false);
    }

如果蓝牙STATE_TURNING_ON或者STATE_TURNING_OFF时需要把mSwitch置为不能点击作用。

4.3、BluetoothSettings.updateContent()
   //BluetoothSettings.java
    private void updateContent(int bluetoothState) {
        final PreferenceScreen preferenceScreen = getPreferenceScreen();
        int messageId = 0;

        switch (bluetoothState) {
            case BluetoothAdapter.STATE_ON:
                preferenceScreen.removeAll();
                preferenceScreen.setOrderingAsAdded(true);
                mDevicePreferenceMap.clear();

                if (isUiRestricted()) {
                    messageId = R.string.bluetooth_empty_list_user_restricted;
                    break;
                }
                添加配对过的或已经配对蓝牙
                // Paired devices category
                if (mPairedDevicesCategory == null) {
                    mPairedDevicesCategory = new PreferenceCategory(getActivity());
                } else {
                    mPairedDevicesCategory.removeAll();
                }
                addDeviceCategory(mPairedDevicesCategory,
                        R.string.bluetooth_preference_paired_devices,
                        BluetoothDeviceFilter.BONDED_DEVICE_FILTER, true);
                int numberOfPairedDevices = mPairedDevicesCategory.getPreferenceCount();

                if (isUiRestricted() || numberOfPairedDevices <= 0) {
                    preferenceScreen.removePreference(mPairedDevicesCategory);
                }
                 添加扫描到的所有蓝牙
                // Available devices category
                if (mAvailableDevicesCategory == null) {
                    mAvailableDevicesCategory = new BluetoothProgressCategory(getActivity());
                    mAvailableDevicesCategory.setSelectable(false);
                } else {
                    mAvailableDevicesCategory.removeAll();
                }
                addDeviceCategory(mAvailableDevicesCategory,
                        R.string.bluetooth_preference_found_devices,
                        BluetoothDeviceFilter.UNBONDED_DEVICE_FILTER, mInitialScanStarted);
                int numberOfAvailableDevices = mAvailableDevicesCategory.getPreferenceCount();

                if (!mInitialScanStarted) {
                    startScanning();
                }

                if (mMyDevicePreference == null) {
                    mMyDevicePreference = new Preference(getActivity());
                }

                mMyDevicePreference.setSummary(getResources().getString(
                            R.string.bluetooth_is_visible_message, mLocalAdapter.getName()));
                mMyDevicePreference.setSelectable(false);
                preferenceScreen.addPreference(mMyDevicePreference);
                更新MENU菜单的选项
                getActivity().invalidateOptionsMenu();

                // mLocalAdapter.setScanMode is internally synchronized so it is okay for multiple
                // threads to execute.
                if (mInitiateDiscoverable) {
                    // Make the device visible to other devices.
                    mLocalAdapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE);
                    mInitiateDiscoverable = false;
                }
                return; // not break

            case BluetoothAdapter.STATE_TURNING_OFF:
                messageId = R.string.bluetooth_turning_off;
                break;

            case BluetoothAdapter.STATE_OFF:
                setOffMessage();
                if (isUiRestricted()) {
                    messageId = R.string.bluetooth_empty_list_user_restricted;
                }
                break;

            case BluetoothAdapter.STATE_TURNING_ON:
                messageId = R.string.bluetooth_turning_on;
                mInitialScanStarted = false;
                break;
        }

        setDeviceListGroup(preferenceScreen);
        removeAllDevices();
        if (messageId != 0) {
            mEmptyView.setText(messageId);
        }
        if (!isUiRestricted()) {
            getActivity().invalidateOptionsMenu();
        }
    }

上面代码看起很多,其实就是当蓝牙开或关时更新界面布局和文字等信息。上面蓝牙状态有四种,STATE_TURNING_ON、STATE_ON、STATE_TURNING_OFF、STATE_OFF,如果蓝牙STATE_TURNING_ON或者STATE_TURNING_OFF时需要把Switch bar置为不能点击作用。

4.4、BluetoothSettings.onOptionsItemSelected()菜单选项功能
//BluetoothSettings.java
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case MENU_ID_SCAN:扫描附近可用蓝牙
                if (mLocalAdapter.getBluetoothState() == BluetoothAdapter.STATE_ON) {
                    MetricsLogger.action(getActivity(), MetricsLogger.ACTION_BLUETOOTH_SCAN);
                    startScanning();
                }
                return true;

            case MENU_ID_RENAME_DEVICE:蓝牙重新命名
                MetricsLogger.action(getActivity(), MetricsLogger.ACTION_BLUETOOTH_RENAME);
                new BluetoothNameDialogFragment().show(
                        getFragmentManager(), "rename device");
                return true;

            case MENU_ID_SHOW_RECEIVED:显示接收文件
                MetricsLogger.action(getActivity(), MetricsLogger.ACTION_BLUETOOTH_FILES);
                Intent intent = new Intent(BTOPP_ACTION_OPEN_RECEIVED_FILES);
                getActivity().sendBroadcast(intent);
                return true;
        }
        return super.onOptionsItemSelected(item);
    }

蓝牙界面大致就这样了,其他状态的改变暂时没有详细列出,涉及到BluetoothAdapter的代码不在Settings中这个后续深入了解。

 历史上的今天

  1. 2024: lnmp安装记录(0条评论)
  2. 2024: git revert简单记录(1条评论)
  3. 2023: JNI异常的使用(0条评论)
  4. 2022: 自定义SeekBar样式(0条评论)
  5. 2019: 沈从文 : 独处(0条评论)
版权声明 1、 本站名称: 91易搜
2、 本站网址: 91es.com3xcn.com
3、 本站内容: 部分来源于网络,仅供学习和参考,若侵权请留言
3、 本站申明: 个人流水账日记,内容并不保证有效

暂无评论

暂无评论...

随机推荐

余光中:等你 在雨中

等你 在雨中 在造虹的雨中蝉声沉落 蛙声升起一池的红莲如红焰 在雨中 你来不来都一样 竟感觉每朵莲都像你尤其隔著黄昏 隔著这样的细雨 永恒 刹那 刹那 永恒等你 在时间之外在时间之内 等你 在刹那 在永恒 如果你的手在我的手里 此刻如果你的清芬...

[摘]查找当前目录下所有文件某一行的内容

前言在做monkey时,会间隔把当前所有应用的内存占用打印出来,因此为了方便查看内存是否有持续增长,会使用命令查看所有dump的文件内容。好记性不如烂笔头正文以下在Window系统中的git bash环境中测试(或者算是Linux环境)find . -type f -name “*.tx...

JNI动态注册封装C++版

前言之前JNI一直用C语言写,但发现Android Framework中大都用C++写,为了阅读方便,改为C++。其实C++跟C语言写法一样的,只不过C++更简洁些。正文修改点,举个例子不同点hello.c文件后缀改为hello.cpp,还有就是C++传入的参数更少,看起来更简洁。he...

Android Studio的Gradle下载慢

前言新建或者导入Android Studio工程,由于各种原因,Gradle下载慢或者更本无法下载,因此需要替换为国内的代理。记录于此,方便自己查阅。正文解决方法:使用阿里仓库服务替换,更多内容可以访问这个:https://maven.aliyun.com/mvn/view具体操作:...

沈从文 :生命

我好像为什么事情很悲哀,我想起“生命”。有什么人能用绿竹作弓矢,射入云空,永不落下?我之想象,犹如长箭,向云空射去,去即不返。长箭所注,在碧蓝而明静之广大虚空。明智者若善用其明智,即可从此云空中,读示一小文,文中有微叹与沉默,色与香,爱和怨。无著者姓名。无年月。无故事。无……然而内容极柔美。虚空...

王蒙:永远的巴金

在这个星空之夜,巴金走了。如果设想一下近百年来最受欢迎和影响最大的一部长篇小说,我想应该是巴金的《家》。早在小时候,我的母亲与姨母就在议论鸣凤和觉慧,梅表姐和琴,觉新觉民高老太爷和老不死的冯乐山,且议且叹,如数家珍。而等到我自己迷于阅读的时候,我宁愿读《灭亡》和《新生》,因为这两本书里写了革命,...