自动化零件服务商 - 供应SMC,FESTO,CKD全新正品气动元件
自动化零件服务商 - 供应SMC,FESTO,CKD全新正品气动元件
自动化零件服务商 - 供应SMC,FESTO,CKD全新正品气动元件

源码: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中对蓝牙的描述。

  1. ......
  2. <!-- Bluetooth -->
  3. <dashboard-tile
  4. android:id="@+id/bluetooth_settings"
  5. android:fragment="com.android.settings.bluetooth.BluetoothSettings"
  6. android:icon="@drawable/ic_settings_bluetooth"
  7. android:title="@string/bluetooth_settings_title" />
  8. ......
复制

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

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

0、BluetoothSettings.java的继承关系

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

  1. public final class BluetoothSettings extends DeviceListPreferenceFragment implements Indexable {
  2. ......
  3. }
  4. public abstract class DeviceListPreferenceFragment extends
  5. RestrictedSettingsFragment implements BluetoothCallback {
  6. ......
  7. }
  8. public abstract class RestrictedSettingsFragment extends SettingsPreferenceFragment {
  9. ......
  10. }
  11. public abstract class SettingsPreferenceFragment extends InstrumentedPreferenceFragment
  12. implements DialogCreatable {
  13. ......
  14. }
  15. public abstract class InstrumentedPreferenceFragment extends PreferenceFragment {
  16. ......
  17. }
  18. public abstract class PreferenceFragment extends Fragment implements
  19. PreferenceManager.OnPreferenceTreeClickListener {
  20. ......
  21. }
复制

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

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

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

1、DeviceListPreferenceFragment.onCreate()

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

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

1.1、BluetoothSettings.addPreferencesForActivity()

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

  1. @Override
  2. void addPreferencesForActivity() {
  3. addPreferencesFromResource(R.xml.bluetooth_settings);
  4. setHasOptionsMenu(true);
  5. }
复制

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

  1. <PreferenceScreen
  2. xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:title="@string/bluetooth_settings" >
  4. </PreferenceScreen>
复制

2、BluetoothSettings.onActivityCreated()

  1. // BluetoothSettings.java
  2. @Override
  3. public void onActivityCreated(Bundle savedInstanceState) {
  4. ......
  5. 一开始进入显示空的界面(蓝牙没有开启时的界面)
  6. mEmptyView = (TextView) getView().findViewById(android.R.id.empty);
  7. getListView().setEmptyView(mEmptyView);
  8. mEmptyView.setGravity(Gravity.START | Gravity.CENTER_VERTICAL);
  9. 初始化mSwitchBar蓝牙开关键
  10. final SettingsActivity activity = (SettingsActivity) getActivity();
  11. mSwitchBar = activity.getSwitchBar();
  12. 2.1 初始化mBluetoothEnabler
  13. mBluetoothEnabler = new BluetoothEnabler(activity, mSwitchBar);
  14. 显示SwitchBar开关
  15. mBluetoothEnabler.setupSwitchBar();
  16. }
复制

2.1 初始化mBluetoothEnabler

  1.   //BluetoothEnabler.java
  2. public BluetoothEnabler(Context context, SwitchBar switchBar) {
  3. ......
  4. 初始化LocalBluetoothManager
  5. LocalBluetoothManager manager = Utils.getLocalBtManager(context);
  6. if (manager == null) {
  7. 如果不支持,就把Switchbar设置为不能使用// Bluetooth is not supported
  8. mLocalAdapter = null;
  9. mSwitch.setEnabled(false);
  10. } else {
  11. mLocalAdapter = manager.getBluetoothAdapter();
  12. }
  13. mIntentFilter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
  14. }
复制

4、BluetoothSettings.onResume()

  1.   //BluetoothSettings.java
  2. @Override
  3. public void onResume() {
  4. // resume BluetoothEnabler before calling super.onResume() so we don't get
  5. // any onDeviceAdded() callbacks before setting up view in updateContent()
  6. if (mBluetoothEnabler != null) {
  7. 4.1 更新蓝牙开关的状态和注册广播
  8. mBluetoothEnabler.resume(getActivity());
  9. }
  10. ......
  11. 检测是否被限制操作蓝牙
  12. if (isUiRestricted()) {
  13. setDeviceListGroup(getPreferenceScreen());
  14. removeAllDevices();
  15. mEmptyView.setText(R.string.bluetooth_empty_list_user_restricted);
  16. return;
  17. }
  18. 注册蓝牙名字改变广播(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED)
  19. getActivity().registerReceiver(mReceiver, mIntentFilter);
  20. if (mLocalAdapter != null) {
  21. 4.3、更新蓝牙状态
  22. updateContent(mLocalAdapter.getBluetoothState());
  23. }
  24. }
复制
4.1、mBluetoothEnabler.resume()
  1.   //BluetoothEnabler.java
  2. public void resume(Context context) {
  3. if (mLocalAdapter == null) {
  4. mSwitch.setEnabled(false);
  5. return;
  6. }
  7. ......
  8. // Bluetooth state is not sticky, so set it manually
  9. 更新蓝牙开关状态(STATE_TURNING_ONSTATE_ONSTATE_TURNING_OFFSTATE_OFF
  10. handleStateChanged(mLocalAdapter.getBluetoothState());
  11. 4.2 监听Switch bar 开关的改变事件
  12. mSwitchBar.addOnSwitchChangeListener(this);
  13. 注册蓝牙状态改变广播(BluetoothAdapter.ACTION_STATE_CHANGED)
  14. mContext.registerReceiver(mReceiver, mIntentFilter);
  15. mValidListener = true;
  16. }
复制
4.2、  监听Switch bar 开关的改变事件
  1. @Override
  2. public void onSwitchChanged(Switch switchView, boolean isChecked) {
  3. // Show toast message if Bluetooth is not allowed in airplane mode
  4. 飞行模式时不能改变蓝牙
  5. if (isChecked &&
  6. !WirelessUtils.isRadioAllowed(mContext, Settings.Global.RADIO_BLUETOOTH)) {
  7. Toast.makeText(mContext, R.string.wifi_in_airplane_mode, Toast.LENGTH_SHORT).show();
  8. // Reset switch to off
  9. 正在更新状态时设置不能点击
  10. switchView.setChecked(false);
  11. }
  12. MetricsLogger.action(mContext, MetricsLogger.ACTION_BLUETOOTH_TOGGLE, isChecked);
  13. 更新蓝牙状态
  14. if (mLocalAdapter != null) {
  15. mLocalAdapter.setBluetoothEnabled(isChecked);
  16. }
  17. 正在更新状态时设置不能点击
  18. mSwitch.setEnabled(false);
  19. }
复制

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

4.3、BluetoothSettings.updateContent()
  1.   //BluetoothSettings.java
  2. private void updateContent(int bluetoothState) {
  3. final PreferenceScreen preferenceScreen = getPreferenceScreen();
  4. int messageId = 0;
  5. switch (bluetoothState) {
  6. case BluetoothAdapter.STATE_ON:
  7. preferenceScreen.removeAll();
  8. preferenceScreen.setOrderingAsAdded(true);
  9. mDevicePreferenceMap.clear();
  10. if (isUiRestricted()) {
  11. messageId = R.string.bluetooth_empty_list_user_restricted;
  12. break;
  13. }
  14. 添加配对过的或已经配对蓝牙
  15. // Paired devices category
  16. if (mPairedDevicesCategory == null) {
  17. mPairedDevicesCategory = new PreferenceCategory(getActivity());
  18. } else {
  19. mPairedDevicesCategory.removeAll();
  20. }
  21. addDeviceCategory(mPairedDevicesCategory,
  22. R.string.bluetooth_preference_paired_devices,
  23. BluetoothDeviceFilter.BONDED_DEVICE_FILTER, true);
  24. int numberOfPairedDevices = mPairedDevicesCategory.getPreferenceCount();
  25. if (isUiRestricted() || numberOfPairedDevices <= 0) {
  26. preferenceScreen.removePreference(mPairedDevicesCategory);
  27. }
  28. 添加扫描到的所有蓝牙
  29. // Available devices category
  30. if (mAvailableDevicesCategory == null) {
  31. mAvailableDevicesCategory = new BluetoothProgressCategory(getActivity());
  32. mAvailableDevicesCategory.setSelectable(false);
  33. } else {
  34. mAvailableDevicesCategory.removeAll();
  35. }
  36. addDeviceCategory(mAvailableDevicesCategory,
  37. R.string.bluetooth_preference_found_devices,
  38. BluetoothDeviceFilter.UNBONDED_DEVICE_FILTER, mInitialScanStarted);
  39. int numberOfAvailableDevices = mAvailableDevicesCategory.getPreferenceCount();
  40. if (!mInitialScanStarted) {
  41. startScanning();
  42. }
  43. if (mMyDevicePreference == null) {
  44. mMyDevicePreference = new Preference(getActivity());
  45. }
  46. mMyDevicePreference.setSummary(getResources().getString(
  47. R.string.bluetooth_is_visible_message, mLocalAdapter.getName()));
  48. mMyDevicePreference.setSelectable(false);
  49. preferenceScreen.addPreference(mMyDevicePreference);
  50. 更新MENU菜单的选项
  51. getActivity().invalidateOptionsMenu();
  52. // mLocalAdapter.setScanMode is internally synchronized so it is okay for multiple
  53. // threads to execute.
  54. if (mInitiateDiscoverable) {
  55. // Make the device visible to other devices.
  56. mLocalAdapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE);
  57. mInitiateDiscoverable = false;
  58. }
  59. return; // not break
  60. case BluetoothAdapter.STATE_TURNING_OFF:
  61. messageId = R.string.bluetooth_turning_off;
  62. break;
  63. case BluetoothAdapter.STATE_OFF:
  64. setOffMessage();
  65. if (isUiRestricted()) {
  66. messageId = R.string.bluetooth_empty_list_user_restricted;
  67. }
  68. break;
  69. case BluetoothAdapter.STATE_TURNING_ON:
  70. messageId = R.string.bluetooth_turning_on;
  71. mInitialScanStarted = false;
  72. break;
  73. }
  74. setDeviceListGroup(preferenceScreen);
  75. removeAllDevices();
  76. if (messageId != 0) {
  77. mEmptyView.setText(messageId);
  78. }
  79. if (!isUiRestricted()) {
  80. getActivity().invalidateOptionsMenu();
  81. }
  82. }
复制

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

4.4、BluetoothSettings.onOptionsItemSelected()菜单选项功能
  1. //BluetoothSettings.java
  2. @Override
  3. public boolean onOptionsItemSelected(MenuItem item) {
  4. switch (item.getItemId()) {
  5. case MENU_ID_SCAN:扫描附近可用蓝牙
  6. if (mLocalAdapter.getBluetoothState() == BluetoothAdapter.STATE_ON) {
  7. MetricsLogger.action(getActivity(), MetricsLogger.ACTION_BLUETOOTH_SCAN);
  8. startScanning();
  9. }
  10. return true;
  11. case MENU_ID_RENAME_DEVICE:蓝牙重新命名
  12. MetricsLogger.action(getActivity(), MetricsLogger.ACTION_BLUETOOTH_RENAME);
  13. new BluetoothNameDialogFragment().show(
  14. getFragmentManager(), "rename device");
  15. return true;
  16. case MENU_ID_SHOW_RECEIVED:显示接收文件
  17. MetricsLogger.action(getActivity(), MetricsLogger.ACTION_BLUETOOTH_FILES);
  18. Intent intent = new Intent(BTOPP_ACTION_OPEN_RECEIVED_FILES);
  19. getActivity().sendBroadcast(intent);
  20. return true;
  21. }
  22. return super.onOptionsItemSelected(item);
  23. }
复制

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

自动化零件服务商 - 供应SMC,FESTO,CKD全新正品气动元件

相关文章

自动化零件服务商 - 供应SMC,FESTO,CKD全新正品气动元件

暂无评论

none
暂无评论...