现在的位置: 首页 > 综合 > 正文

Android蓝牙Settings之界面

2013年12月09日 ⁄ 综合 ⁄ 共 7123字 ⁄ 字号 评论关闭

布局图如下:

 

1.ActionBar:Switch

在Android4.0中,在主界面Settings中定义了很多内部子空类,例如:

public static class BluetoothSettingsActivity extends Settings
在Mainifest.xml中,配置了一些对应的fragment。例如:

<activityandroid:name="Settings$BluetoothSettingsActivity"

               android:label="@string/bluetooth_settings_title"

               android:clearTaskOnLaunch="true">

           <intent-filter>

                <actionandroid:name="android.intent.action.MAIN" />

               <action android:name="android.settings.BLUETOOTH_SETTINGS"/>

               <categoryandroid:name="android.intent.category.VOICE_LAUNCH" />

               <category android:name="com.android.settings.SHORTCUT"/>

               <category android:name="android.intent.category.DEFAULT"/>

           </intent-filter>

           <meta-dataandroid:name="com.android.settings.FRAGMENT_CLASS"

                android:value="com.android.settings.bluetooth.BluetoothSettings"/>

           <meta-dataandroid:name="com.android.settings.TOP_LEVEL_HEADER_ID"

               android:resource="@id/bluetooth_settings" />

       </activity>

 

可以看到他对应的fragment是

com.android.settings.bluetooth.BluetoothSettings

所以说我们从一级界面Settings点击相应的header跳转到BT的设置的界面的时候,实际上是启动相应的Activity加上fragment。

这 里当然是BluetoothSettingsActivity加上BluetoothSettings,对于ActionBar这部分,我们可以看到是由两部分主城,其中一部分是由icon和文字来表示当前的界面,其中icon始终没有变,而文字是要相应的 变化的,而这个文字的设置就在 Mainfest中配置的: android:label="@string/bluetooth_settings_title"。 另一部分是一个Switcher来控制蓝牙的关闭。这个switch就是一个widget,他的基本关系:public
class Switch extendsCompoundButton。 Switch是在BluetoothSettings代码中添加的:

 activity.getActionBar().setCustomView(actionBarSwitch,new ActionBar.LayoutParams(

                       ActionBar.LayoutParams.WRAP_CONTENT,

                       ActionBar.LayoutParams.WRAP_CONTENT,

                       Gravity.CENTER_VERTICAL | Gravity.RIGHT));

 

后面又将actionBarSwitch传入到BluetoothEnabler,通过BluetoothEnabler来控制开关的逻辑。

2.PreferenceScreen

这个就是ActionBar下面的这部分,可以从图中看到这部分主要包含了本机名字Hike706, 已配对的设备,可用设备,和一个搜索设备的action按钮。

这部分内容是要打开BT设备后,才会显示出来。

(1).Preference, 本机名

相关代码:

if (mMyDevicePreference == null) {
                   mMyDevicePreference = new Preference(getActivity());
                }
mMyDevicePreference.setTitle(mLocalAdapter.getName());

preferenceScreen.addPreference(mMyDevicePreference);

得到本机的名字调用关系:LocalBluetoothAdapter.getName()------->BluetoothAdapter.getName()(处于Framework了,在framework会分析这部分代码)。

 

还有前面的那个电话图标是怎么产生的。

if(getResources().getBoolean(com.android.internal.R.bool.config_voice_capable)) {

                   mMyDevicePreference.setIcon(R.drawable.ic_bt_cellphone);    // for phones

                }else {

                   mMyDevicePreference.setIcon(R.drawable.ic_bt_laptop);   // for tablets, etc.

                }

可以看到就两个图标,一个是手机,一个是平板。

具体的是由 com.android.internal.R.bool.config_voice_capable这个确定的,存在于framework,后面分析。

 

(2).PreferenceCategory (已配对的设备)

首先是界面部分:

相关代码:

 if(mPairedDevicesCategory == null) {

                   mPairedDevicesCategory = new PreferenceCategory(getActivity());

                }else {

                   mPairedDevicesCategory.removeAll();

                }

               addDeviceCategory(mPairedDevicesCategory,

                       R.string.bluetooth_preference_paired_devices,

                       BluetoothDeviceFilter.BONDED_DEVICE_FILTER);


其中addDeviceCategory会将所有已配对的设备都添加进这一组:

相关代码:

 

preferenceGroup.setTitle(titleId);

       getPreferenceScreen().addPreference(preferenceGroup);

       setFilter(filter);

       setDeviceListGroup(preferenceGroup);

       addCachedDevices();

       preferenceGroup.setEnabled(true);

可以看到除了将preferenceGroup添加到PreferenceScreen(),后面几句就是向preferenceGroup添加设备:

DeviceListPreferenceFragment:addCachedDevices();

void addCachedDevices() {

       Collection<CachedBluetoothDevice> cachedDevices =

               mLocalManager.getCachedDeviceManager().getCachedDevicesCopy();

        for(CachedBluetoothDevice cachedDevice : cachedDevices) {

           onDeviceAdded(cachedDevice);

        }

    }

但是在这个函数中

if (mDevicePreferenceMap.get(cachedDevice) != null) {

            return;

        }

 

        // Preventupdates while the list shows one of the state messages

        if(mLocalAdapter.getBluetoothState() != BluetoothAdapter.STATE_ON) return;

 

        if(mFilter.matches(cachedDevice.getDevice())) {

           createDevicePreference(cachedDevice);

        }

可以看到会根据Filter尽心过滤。在这里我们的filter是BluetoothDeviceFilter.BONDED_DEVICE_FILTER。所以只会create配对的设备。

 

void createDevicePreference(CachedBluetoothDevice cachedDevice) {

       BluetoothDevicePreference preference = new BluetoothDevicePreference(

                getActivity(),cachedDevice);

 

       initDevicePreference(preference);

       mDeviceListGroup.addPreference(preference);

       mDevicePreferenceMap.put(cachedDevice, preference);

    }

这个函数就是最终生成我们看到一个个已配对设备的列表。

这个函数就是遍历出cachedDevices中的元素依次添加进preferenceGroup。

cachedDevices:LocalBluetoothManager---->CachedBluetoothDeviceManager:addDevice

从这条路径来看,cachedDevices最终是通过CachedBluetoothDeviceManager添加进来的,

那addDevice什么时候调用呢?

是BluetoothEventManager接收到相应的广播后调用CachedBluetoothDeviceManager:addDevice。

相关代码:

CachedBluetoothDevice cachedDevice =mDeviceManager.findDevice(device);

            if(cachedDevice == null) {

               cachedDevice = mDeviceManager.addDevice(mLocalAdapter, mProfileManager,device);

               Log.d(TAG, "DeviceFoundHandler created new CachedBluetoothDevice:"

                       + cachedDevice);

                //callback to UI to create Preference for new device

               dispatchDeviceAdded(cachedDevice);

            }

 

不仅将cachedDevice添加给 mDeviceManager,而且还会通知界面更新。

至于

mDeviceManager.findDevice(device);中的device是从何而来,是由接收BluetoothDevice.ACTION_BOND_STATE_CHANGED这个广播所带的信息而来。这个广播是从framework发送而来。后面framework会分析。

广播接收代码:

 

private finalBroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {

        @Override

        public void onReceive(Context context,Intent intent) {

           Log.v(TAG, "Received " + intent.getAction());

 

            Stringaction = intent.getAction();

           BluetoothDevice device = intent

                   .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);

 

            Handlerhandler = mHandlerMap.get(action);

            if(handler != null) {

               handler.onReceive(context, intent, device);

            }

        }

    };

可以看到device的信息:

 BluetoothDevicedevice = intent

                   .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);

(3).ProgressCategory-->ProgressCategoryBase----->PreferenceCategory.(已发现的设备)

可以看到最终也是一个PreferenceCategory, 只不过是增加了了一个“触摸可配对”的元件(在没有扫描的时候)。在扫描的时候,会将其替换掉“正在搜索”和一个旋转的ProgressBar,其他的就完全一样。

相关代码:

if (mAvailableDevicesCategory == null) {

                   mAvailableDevicesCategory = new ProgressCategory(getActivity(), null);

                }else {

                   mAvailableDevicesCategory.removeAll();

                }

                addDeviceCategory(mAvailableDevicesCategory,

                       R.string.bluetooth_preference_found_devices,

                       BluetoothDeviceFilter.UNBONDED_DEVICE_FILTER);

其他的流程基本和(2)的流程一样,只不过是filter换成了BluetoothDeviceFilter.UNBONDED_DEVICE_FILTER。所以就只会添加cachedDevices中没有配对的设备到这一组来。但是当开始扫描后会不断更新这一组的列表。

对于已配对的设备和可用的设备之间界面的区别:

 

 

对于这两个界面的构造都是在BluetoothDevicePreference创建中实现的。

相关代码:

      

 if(cachedDevice.getBondState() == BluetoothDevice.BOND_BONDED) {

           setWidgetLayoutResource(R.layout.preference_bluetooth);

        }

当处于BluetoothDevice.BOND_BONDED状态的时候会在处于没有配对状态的后面添加一个R.layout.preference_bluetooth, 这个包含了详细信息按钮。

当开始扫描后:回到BluetoothEventManager, 接收到BluetoothDevice.ACTION_FOUND的广播:

 

CachedBluetoothDevice cachedDevice =mDeviceManager.findDevice(device);

            if(cachedDevice == null) {

               cachedDevice = mDeviceManager.addDevice(mLocalAdapter, mProfileManager,device);

               Log.d(TAG, "DeviceFoundHandler created new CachedBluetoothDevice:"

                       + cachedDevice);

                //callback to UI to create Preference for new device

               dispatchDeviceAdded(cachedDevice);

            }


添加设备到CachedBluetoothDeviceManager后,dispatchDeviceAdded(cachedDevice);就会通知界面更新

 

 synchronized (mCallbacks) {
            for(BluetoothCallback callback : mCallbacks) {
               callback.onDeviceAdded(cachedDevice);
            }

因为在DeviceListPreferenceFragment中有注册callback,所以会调用DeviceListPreferenceFragment中的onDeviceAdded。

mLocalManager.getEventManager().registerCallback(this);。

接后面的步骤参考(2)。

(4).menus:

menu.add(Menu.NONE, MENU_ID_SCAN, 0, textId).setEnabled(bluetoothIsEnabled && !isDiscovering).setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);

所以他会一直作为ActionBar显示在底部。而其他的会隐藏在menu中

MENU_ID_SCAN

MENU_ID_RENAME_DEVICE

MENU_ID_VISIBILITY_TIMEOUT

MENU_ID_SHOW_RECEIVED

MENU_ID_ADVANCED_SETTING


蓝牙settings界面大概就是这样。 



 










抱歉!评论已关闭.