在上一篇文章中,我们详细分析了android是如何解析蓝牙反馈上来的搜索到的设备信息,本文将会继续分析这些信息到了上层之后是如何处理。

8、inquiry result引起的上层变化

我们知道inquiry result引起的上层变化是通过向上层回报device found的signal来实现的。在jni层收到这个signal之后,会调用java层的onDeviceFound接口,这个地方为什么会调用我就不详细解释了,看了我之前的文章,这个地方应该是轻车熟路了。直接分析onDeviceFound函数:

 private void onDeviceFound(String address, String[] properties) {
if (properties == null) {
Log.e(TAG, "ERROR: Remote device properties are null");
return;
}
//把address和对应的properties保存
addDevice(address, properties);
}
private void addDevice(String address, String[] properties) {
BluetoothDeviceProperties deviceProperties =
mBluetoothService.getDeviceProperties();
//保存address和对应的properties
deviceProperties.addProperties(address, properties);
//得到rssi,class,name
String rssi = deviceProperties.getProperty(address, "RSSI");
String classValue = deviceProperties.getProperty(address, "Class");
String name = deviceProperties.getProperty(address, "Name");
short rssiValue;
// For incoming connections, we don't get the RSSI value. Use a default of MIN_VALUE.
// If we accept the pairing, we will automatically show it at the top of the list.
if (rssi != null) {
rssiValue = (short)Integer.valueOf(rssi).intValue();
} else {
//得到short的最小值
rssiValue = Short.MIN_VALUE;
}
if (classValue != null) {
//有clasevalue我们会产生action_found的broadcast
Intent intent = new Intent(BluetoothDevice.ACTION_FOUND);
intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
intent.putExtra(BluetoothDevice.EXTRA_CLASS,
new BluetoothClass(Integer.valueOf(classValue)));
intent.putExtra(BluetoothDevice.EXTRA_RSSI, rssiValue);
intent.putExtra(BluetoothDevice.EXTRA_NAME, name); mContext.sendBroadcast(intent, BLUETOOTH_PERM);
} else {
//对于不知道class的设备,我们并不会上报
log ("ClassValue: " + classValue + " for remote device: " + address + " is null");
}
}

很明显,一般而言,会把这些信息通过action_found的broadcast回报到上层的app,供对应的app使用。我们去settings中看看吧,这个broadcast该如何处理啊,呵呵~~

在settings中对这个broadcast的处理就只有一个:

addHandler(BluetoothDevice.ACTION_FOUND, new DeviceFoundHandler());

所以,我们直接去看DeviceFoundHandler是怎么实现的:

//device found的处理
private class DeviceFoundHandler implements Handler {
public void onReceive(Context context, Intent intent,
BluetoothDevice device) {
//得到rssi,class,name
short rssi = intent.getShortExtra(BluetoothDevice.EXTRA_RSSI, Short.MIN_VALUE);
BluetoothClass btClass = intent.getParcelableExtra(BluetoothDevice.EXTRA_CLASS);
String name = intent.getStringExtra(BluetoothDevice.EXTRA_NAME);
// TODO Pick up UUID. They should be available for 2.1 devices.
// Skip for now, there's a bluez problem and we are not getting uuids even for 2.1.
//cachedDevice中是否有对应的设备
CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
if (cachedDevice == null) {
//若是没有,则把device加进去
cachedDevice = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, device);
Log.d(TAG, "DeviceFoundHandler created new CachedBluetoothDevice: "
+ cachedDevice);
// callback to UI to create Preference for new device
//创建对应的preference
dispatchDeviceAdded(cachedDevice);
}
//设置cached device的属性,并显示出来
cachedDevice.setRssi(rssi);
cachedDevice.setBtClass(btClass);
cachedDevice.setName(name);
cachedDevice.setVisible(true);
}
}

所以,这里就是在ui上显示对应的搜索到的内容了。

到这里,我们就完成从点击搜索到开始显示第一个搜索到的设备之间的流程的分析。下面就是接着搜索到的设备的显示,这个操作是雷同的,直到搜索结束。底层表示搜索结束的event是inquiry complete,收到这个event表示我们的搜索就结束了,那么上层对这个event是如何处理的呢?我们继续分析。


9、inquiry complete event的处理

在分析inquirycomplete之前,我们同样来看一下spec中是如何定义这个event的:

看起来很简单啊,就返回了一个status的参数,这个参数若是为0就表示success,若是不为0则根据返回值有各种返回错误码。在core spec中类似只返回status的event还是蛮多的,后面遇到的话我就只提一下,不会再截图了哦,大家可以自己去看具体的spec。

具体的inquiry complete event的处理如下:

static inline void inquiry_complete_evt(int index, uint8_t status)
{
int adapter_type;
struct btd_adapter *adapter; //inquiry失败
if (status) {
error("Inquiry Failed with status 0x%02x", status);
return;
} //找到对应的adapter
adapter = manager_find_adapter_by_id(index);
if (!adapter) {
error("No matching adapter found");
return;
} //得到对应的type,le or bredr
adapter_type = get_adapter_type(index); if (adapter_type == BR_EDR_LE &&
adapter_has_discov_sessions(adapter)) {
//LE我们忽略
int err = hciops_start_scanning(index, TIMEOUT_BR_LE_SCAN);
if (err < 0)
set_state(index, DISCOV_HALTED);
} else {
//bredr设置state位halted
set_state(index, DISCOV_HALTED);
}
}

9.1 设置state为DISCOV_HALTED

这个state的设置代码如下:

  switch (dev->discov_state) {
case DISCOV_HALTED:
//得到adapter的state
if (adapter_get_state(adapter) == STATE_SUSPENDED)
return; //resolv name是否enable,并且有discov的session
if (is_resolvname_enabled() &&
adapter_has_discov_sessions(adapter))
//resolve name
adapter_set_state(adapter, STATE_RESOLVNAME);
else
//否则就直接设为idle了
adapter_set_state(adapter, STATE_IDLE);
break;
这里其实就是去进行resolve name:
case STATE_RESOLVNAME:
resolve_names(adapter);
break;

9.2 resolve name的分析

static inline void resolve_names(struct btd_adapter *adapter)
{
int err; //这个必须先设置adapter的state才行
if (adapter->state != STATE_RESOLVNAME)
return; err = adapter_resolve_names(adapter);
//err < 0是表示有错误,这里设为idle,没有错误的情况下,这里是不会走到idle的哦
if (err < 0)
adapter_set_state(adapter, STATE_IDLE);
} int adapter_resolve_names(struct btd_adapter *adapter)
{
struct remote_dev_info *dev, match;
int err; /* Do not attempt to resolve more names if on suspended state */
if (adapter->state == STATE_SUSPENDED)
return 0; memset(&match, 0, sizeof(struct remote_dev_info));
bacpy(&match.bdaddr, BDADDR_ANY);
match.name_status = NAME_REQUIRED; //遍历found device中name_required的设备
dev = adapter_search_found_devices(adapter, &match);
if (!dev)
return -ENODATA; /* send at least one request or return failed if the list is empty */
do {
/* flag to indicate the current remote name requested */
dev->name_status = NAME_REQUESTED; //这个应该就是发送remote name request了
err = adapter_ops->resolve_name(adapter->dev_id, &dev->bdaddr); //成功直接返回
if (!err)
break; error("Unable to send HCI remote name req: %s (%d)",
strerror(errno), errno); /* if failed, request the next element */
/* remove the element from the list */
//faile,就直接把这个设备从found device中remove掉
adapter_remove_found_device(adapter, &dev->bdaddr); /* get the next element */
//找下一个name request的设备
dev = adapter_search_found_devices(adapter, &match);
} while (dev); return err;
}

Hciops中resolve name的实现:

static int hciops_resolve_name(int index, bdaddr_t *bdaddr)
{
struct dev_info *dev = &devs[index];
remote_name_req_cp cp;
char addr[18]; ba2str(bdaddr, addr);
DBG("hci%d dba %s", index, addr); memset(&cp, 0, sizeof(cp));
bacpy(&cp.bdaddr, bdaddr);
cp.pscan_rep_mode = 0x02; //remote name request command的发送
if (hci_send_cmd(dev->sk, OGF_LINK_CTL, OCF_REMOTE_NAME_REQ,
REMOTE_NAME_REQ_CP_SIZE, &cp) < 0)
return -errno; return 0;
}

所以,在收到inquiry comple的event之后,我们并没有立即通知上层结束扫描,而是在继续地发送remote name request的command去继续得到设备的名字。而此时,上层根本不知道有这些东西在,它还是老老实实地转着圈圈等待搜索的结束。

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

[置顶] [Android源码分析]inquiry result引起的上层变化分析的更多相关文章

  1. [置顶] Android源码分析-点击事件派发机制

    转载请注明出处:http://blog.csdn.net/singwhatiwanna/article/details/17339857 概述 一直想写篇关于Android事件派发机制的文章,却一直没 ...

  2. [置顶] OpenJDK源码研究笔记(九)-可恨却又可亲的的异常(NullPointerException)

    可恨的异常 程序开发过程中,最讨厌异常了. 异常代表着程序出了问题,一旦出现,控制台会出现一屏又一屏的堆栈错误信息. 看着就让人心烦. 对于一个新人来讲,遇到异常经常会压力大,手忙脚乱,心生畏惧. 可 ...

  3. Android源码之Gallery专题研究(1)

    前言 时光飞逝,从事Android系统开发已经两年了,总想写点什么来安慰自己.思考了很久总是无法下笔,觉得没什么好写的.现在终于决定写一些符合大多数人需求的东西,想必使用过Android手机的人们一定 ...

  4. 编译android源码m、mm、mmm命令的使用

    http://blog.163.com/zz_forward/blog/static/212898222201442873435471/ gcc怎么查看它的默认include路径和库的路径呢? //- ...

  5. [置顶] 我的Android进阶之旅------>如何将Android源码导入Eclipse中来查看(非常实用)

    Android源码下载完成的目录结构如如所示: step1:将.classpath文件拷贝到源代码的根目录 Android源码支持多种IDE,如果是针对APP层做开发的话,建议大家使用Eclipse开 ...

  6. [置顶] Android 高级开发 源码 UI 缓存 网络

    1.Android 源码剖析 性能优化  开源代码 2.Android UI效果源码 3.http://mzh3344258.blog.51cto.com/1823534/d-3 4.微信公众平台开发 ...

  7. Android源码分析(十五)----GPS冷启动实现原理分析

    一:原理分析 主要sendExtraCommand方法中传递两个参数, 根据如下源码可以知道第一个参数传递delete_aiding_data,第二个参数传递null即可. @Override pub ...

  8. Android源码分析(十四)----如何使用SharedPreferencce保存数据

    一:SharedPreference如何使用 此文章只是提供一种数据保存的方式, 具体使用场景请根据需求情况自行调整. EditText添加saveData点击事件, 保存数据. diff --git ...

  9. MTK Android 源码目录分析

    Android 源码目录分析 Android 4.0 |-- abi (application binary interface:应用二进制接口)|-- art (average retrieval ...

随机推荐

  1. jq 图片裁剪

    1.html <div class="jcropbox" style="display: none"> <img src="&quo ...

  2. hdoj 1251 字典树

    代码: #include <stdio.h>#define  MAX    26 typedef struct TrieNode{     int nCount;      struct ...

  3. I/O多路复用之poll

    poll函数和select函数非常相似,但是函数接口不一样. #include <poll.h> int poll(struct pollfd *fdarray, unsigned lon ...

  4. Windows 8 / 8.1 禁用驱动签名最详细图文教程

    Windows 8 鼠标右上角/右下角弹出边栏,选择“设置” 点击“更改电脑设置”: 选择“常规”,右侧拖到底,点击“高级启动”-“立即重启”: 稍后进入恢复页面,选择“疑难解答” 进入疑难解答后,选 ...

  5. Python开发【第一章】:Python简介和入门

    Python简介 Python的创始人为Guido van Rossum.1989年圣诞节期间,在阿姆斯特丹,Guido为了打发圣诞节的无趣,决心开发一个新的脚本解释程序,做为ABC 语言的一种继承. ...

  6. E题 - A+B for Input-Output Practice (IV)

      Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u   Description You ...

  7. A Statistical View of Deep Learning (II): Auto-encoders and Free Energy

    A Statistical View of Deep Learning (II): Auto-encoders and Free Energy With the success of discrimi ...

  8. 【Web Service】WSDL文档

    WSDL文档仅仅是一个简单的XML文档. 它包含一系列描述某个web service的定义. WSDL WSDL 是基于 XML 的语言,用于描述 Web services 以及如何访问它们. WSD ...

  9. Protues中有源蜂鸣器BUZZER不响的解决办法(有图)

    这个是BUZZER有源蜂鸣器的protues连线图(FM是我自己的电压探针,可以删除的) 下面是我个人设置的蜂鸣器的参数(为什么很多人的这个蜂鸣器不响,是参数没有设置正确) 蜂鸣器不响的原因是 Ope ...

  10. open和fopen的区别(转)

    转载自:http://www.cnblogs.com/joeblackzqq/archive/2011/04/11/2013010.html open和fopen的区别: 1.缓冲文件系统缓 冲文件系 ...