[Android源码分析]从spec角度来详细分析inquiry command带来的影响

浏览:
字体:
发布时间:2013-12-11 11:03:04
来源:

上文我们详细介绍了Android是如何通过ui操作到最终发出inquiry command来实现蓝牙的扫描功能的。本文晓东将会和大家一起来看看inquiry command的格式,以及发出这个command后会产生哪些影响。

4、inquiry cmd的格式分析。

在蓝牙core spec中明确定义了inquirycmd的格式已经返回的event。我们来具体看看:

/

Inquiry command的格式[1]

针对这个command的参数设置如下:

/

LAP:在spec上是这样描述这个参数的:“The reserved LAP addresses are 0x9E8B00-0X9E8B3F,The general LAP is 0x9E8B33.”也就是说,LAP的地址范围是0x9E8B00-0X9E8B3F,一般而言我们设为0x9E8B33。从上面的代码我们也可以发现,android中的确使用的是推荐值:uint8_t lap[3] = {0x33, 0x8b, 0x9e };

Inquiry length:这个顾名思义就是扫描的时间长度。上面的LENGTH_BR_INQ的值是0x08,简单计算一下08*1.28s,大概就是10s了,所以,我们从上层才会看到一般的android手机搜索的时间就是10s,若是需要修改,则可以改这边的参数,当然最长不能超过61.44s了。

Num_Responses:就是响应的设备数目,这里设为0就是不限制搜索到的设备数目。当然一般而言,我们都不会设置搜素到的设备的,呵呵~~

这个command发送下去会产生哪些event呢,spec中也是有明确规定的:

A Command Status event shall be sentfrom the BR/EDR Controller to the Host,when the BR/EDRController has started the Inquiry process. Unless filtered, an Inquiry Resultevent shall be created for each BR/EDR Controller which responds to the Inquirymessage. In addition, multiple BR/EDR Controllers which respond to the Inquiremessage may be combined into the same event. An Inquiry Complete event shall begenerated when the Inquiry process has completed.

总的意思就是说,我们首先要产生一个command status的event,这个event产生后就表示蓝牙已经开始扫描设备了。然后会有inquiry resultevent会回报上来。需要注意的有可能多个设备在event中回报上来,所以需要继续解析这个event。在最后,inquiry complete event会上来表示inquiry完成了。所以,下面我们就会主要讨论这几个event。

 

5、command statusevent的处理。

在对event的解析函数中是这样写的:

 

 switch (eh->evt) {        case EVT_CMD_STATUS:                cmd_status(index, ptr);                break;

 

 

 

所以会调用cmd_status这个函数:

 

static inline void cmd_status(int index, void *ptr){        evt_cmd_status *evt = ptr;        uint16_t opcode = btohs(evt->opcode);//很多cmd都会产生这个event,只是唯独对inquiry需要做一些特殊的处理        //若是inquiry的cmd有一个特殊的操作        if (opcode == cmd_opcode_pack(OGF_LINK_CTL, OCF_INQUIRY))                cs_inquiry_evt(index, evt->status);}static inline void cs_inquiry_evt(int index, uint8_t status){        //这里有个inquiry的错误操作        //原本就是打印一个错误的信息,感觉对错误的处理还是有所欠缺啊        if (status) {                error("Inquiry Failed with status 0x%02x", status);                return;        }        //这里在ok的情况下,需要设置状态为inq,主要就是向上层回复discovering的property change        set_state(index, DISCOV_INQ);}Set_State的函数片段:       case DISCOV_SCAN:                               //设置adapter的state                adapter_set_state(adapter, STATE_DISCOV);                break;      adapter_set_state的函数片段:  case STATE_DISCOV:                //设置discov_active标志                discov_active = TRUE;                //向上层回复discovering的property change                emit_property_changed(connection, path,                                        ADAPTER_INTERFACE, "Discovering",                                        DBUS_TYPE_BOOLEAN, &discov_active);                break;从上面的spec分析中我们已经知道cmd status就是表示inquiry开始了,所以我们有必要通知上层了,比如说上层的progress的小圆圈可以转起来了。我们回到上层去看看://这个函数位于eventloop中        } else if (name.equals("Discovering")) {            Intent intent;        //收到discovering的property change的处理            adapterProperties.setProperty(name, propValues[1]);        //根据这个值来发送对应的broadcast            if (propValues[1].equals("true")) {                intent = new Intent(BluetoothAdapter.ACTION_DISCOVERY_STARTED);            } else {                // Stop the discovery.                mBluetoothService.cancelDiscovery();                intent = new Intent(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);            }            mContext.sendBroadcast(intent, BLUETOOTH_PERM);

 

 

 

所以,framework层对这个的处理就是发送一个ACTION_DISCOVERY_STARTED的broadcast,这样所有的receiver就可以动起来了。

6、ACTION_DISCOVERY_STARTED的receiver分析

从代码中我们可以看到这个action一共有两个receiver,一个是静态注册的一个是动态注册是:

6.1 BluetoothDiscoveryReceiver

这个receiver是在settings中的androidmanifest中注册的:

 

                                                                                        
这个receiver的具体操作如下:
public final class BluetoothDiscoveryReceiver extends BroadcastReceiver {    private static final String TAG = "BluetoothDiscoveryReceiver";    @Override    public void onReceive(Context context, Intent intent) {        String action = intent.getAction();        Log.v(TAG, "Received: " + action);        if (action.equals(BluetoothAdapter.ACTION_DISCOVERY_STARTED) ||                action.equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) {                //就是更新共享空间中的扫描开始和扫描结束的时间            LocalBluetoothPreferences.persistDiscoveringTimestamp(context);        }    }}

 

 

 

其实就是更新时间戳,事实上,我们在开始扫描的时候有检查过这个时间戳,这里也就是那个地方用的。

6.2 ScanningStateChangedHandler

这个receiver是一个handler,他的注册如下:

 

addHandler(BluetoothAdapter.ACTION_DISCOVERY_STARTED, new ScanningStateChangedHandler(true));//处理函数如下    private class ScanningStateChangedHandler implements Handler {        private final boolean mStarted;        ScanningStateChangedHandler(boolean started) {            mStarted = started;        }        public void onReceive(Context context, Intent intent,                BluetoothDevice device) {//调用注册的callback中的onScanningStateChanged函数,具体见6.2.1            synchronized (mCallbacks) {                for (BluetoothCallback callback : mCallbacks) {                    callback.onScanningStateChanged(mStarted);                }            }//这个函数就是把上次扫描到的设备拿清除掉,所以,我们会发现在扫描的开始原来的设备就都不见了,具体见6.2.2            mDeviceManager.onScanningStateChanged(mStarted);            LocalBluetoothPreferences.persistDiscoveringTimestamp(context);        }}

 

 

 

6.2.1 注册的callback

从代码中我们可以看到有以下callback:

 

1)DeviceListPreferenceFragment.java    public void onScanningStateChanged(boolean started) {        if (started == false) {	//这个是扫描结束的处理            removeOutOfRangeDevices();        }        updateProgressUi(started);    }    private void updateProgressUi(boolean start) {        //就是那个小圆圈就开始动起来了        if (mDeviceListGroup instanceof ProgressCategory) {            ((ProgressCategory) mDeviceListGroup).setProgress(start);        }    }

 

 

 

6.2.2 mDeviceManager.onScanningStateChanged的分析

 

public synchronized void onScanningStateChanged(boolean started) {        // If starting a new scan, clear old visibility        // Iterate in reverse order since devices may be removed.        //扫描所有的cached的device        for (int i = mCachedDevices.size() - 1; i >= 0; i--) {            CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);                //假如是开始扫描,就是把他不显示了            if (started) {                cachedDevice.setVisible(false);            } else {                //扫描结束,若是他不是已经配对的,并且是不可见的,我们就把它从cacheddevices中remove掉。                //这些设备其实就是那些之前扫描到过,但是这次扫描没有扫描到的设备。                //没有开始就把设备remove掉的一个好处就是,若是这次再次扫描到,我们不需要再加入进去                if (cachedDevice.getBondState() == BluetoothDevice.BOND_NONE &&                        cachedDevice.isVisible() == false) {                    mCachedDevices.remove(cachedDevice);                }            }        }    }

 

 

 

至此,command statusevent的处理就全部ok了,主要就是向上层汇报说我们开始扫描设备了,你可以把ui上上次扫描的设备去除掉,并且把开始扫描的ui上的小圈圈动起来了。

 

若您觉得该文章对您有帮助,请在下面用鼠标轻轻按一下“顶”,哈哈~~·



>更多相关文章
24小时热门资讯
24小时回复排行
资讯 | QQ | 安全 | 编程 | 数据库 | 系统 | 网络 | 考试 | 站长 | 关于东联 | 安全雇佣 | 搞笑视频大全 | 微信学院 | 视频课程 |
关于我们 | 联系我们 | 广告服务 | 免责申明 | 作品发布 | 网站地图 | 官方微博 | 技术培训
Copyright © 2007 - 2024 Vm888.Com. All Rights Reserved
粤公网安备 44060402001498号 粤ICP备19097316号 请遵循相关法律法规
');})();