Android 6.0 Settings源码简单分析之蓝牙(1)

极客导航  2018-08-09 20:41  阅读 118 次 评论 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中这个后续深入了解。

历史上的今天:

本文地址: https://www.125la.com/597.html
关注我们:请关注一下我们站长微信:扫描二维码125啦读书导航的微信号,微信号:yudemi(十三少)
版权声明:本文为原创或转载文章,版权归原作者所有,欢迎分享本文,转载请保留出处!
第一个读书导航

发表评论


表情