[置顶] [Android源码分析]inquiry result引起的上层变化分析
在上一篇文章中,我们详细分析了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引起的上层变化分析的更多相关文章
- [置顶] Android源码分析-点击事件派发机制
转载请注明出处:http://blog.csdn.net/singwhatiwanna/article/details/17339857 概述 一直想写篇关于Android事件派发机制的文章,却一直没 ...
- [置顶] OpenJDK源码研究笔记(九)-可恨却又可亲的的异常(NullPointerException)
可恨的异常 程序开发过程中,最讨厌异常了. 异常代表着程序出了问题,一旦出现,控制台会出现一屏又一屏的堆栈错误信息. 看着就让人心烦. 对于一个新人来讲,遇到异常经常会压力大,手忙脚乱,心生畏惧. 可 ...
- Android源码之Gallery专题研究(1)
前言 时光飞逝,从事Android系统开发已经两年了,总想写点什么来安慰自己.思考了很久总是无法下笔,觉得没什么好写的.现在终于决定写一些符合大多数人需求的东西,想必使用过Android手机的人们一定 ...
- 编译android源码m、mm、mmm命令的使用
http://blog.163.com/zz_forward/blog/static/212898222201442873435471/ gcc怎么查看它的默认include路径和库的路径呢? //- ...
- [置顶] 我的Android进阶之旅------>如何将Android源码导入Eclipse中来查看(非常实用)
Android源码下载完成的目录结构如如所示: step1:将.classpath文件拷贝到源代码的根目录 Android源码支持多种IDE,如果是针对APP层做开发的话,建议大家使用Eclipse开 ...
- [置顶] Android 高级开发 源码 UI 缓存 网络
1.Android 源码剖析 性能优化 开源代码 2.Android UI效果源码 3.http://mzh3344258.blog.51cto.com/1823534/d-3 4.微信公众平台开发 ...
- Android源码分析(十五)----GPS冷启动实现原理分析
一:原理分析 主要sendExtraCommand方法中传递两个参数, 根据如下源码可以知道第一个参数传递delete_aiding_data,第二个参数传递null即可. @Override pub ...
- Android源码分析(十四)----如何使用SharedPreferencce保存数据
一:SharedPreference如何使用 此文章只是提供一种数据保存的方式, 具体使用场景请根据需求情况自行调整. EditText添加saveData点击事件, 保存数据. diff --git ...
- MTK Android 源码目录分析
Android 源码目录分析 Android 4.0 |-- abi (application binary interface:应用二进制接口)|-- art (average retrieval ...
随机推荐
- Javascript基础(2)
开始更咯~~~嘻嘻. ---------------------------------------------------------------------------------- 异常捕获:即 ...
- express 安装与卸载
卸载: npm uninstall -g express安装指定版本: npm install -g express@3.5.0查看版本: express -V注意express -V中的V要大写,不 ...
- SVN版本控制图标不显示的解决方法~
新系统每次装了svn之后,过了一段时间,安装的软件一多就会出现这个问题,哎,收录一下解决方案! 输入:win+R,输入regedit,调出注册表信息,按下Ctrl+F,在注册表里搜索"She ...
- dedecms织梦导航栏二级菜单的实现方法
dede导航下拉菜单,一级栏目增加二级下拉菜单 使用dedecms5.6——5.7 将这段代码贴到templets\default\head.htm文件里<!-- //二级子类下拉菜单,考虑 ...
- SOC
http://marsvaadin.iteye.com/blog/1311438 http://blog.csdn.net/cxxsoft/article/details/12610641
- 我的VSTO之路(三):Word基本知识
原文:我的VSTO之路(三):Word基本知识 在前一篇文章中,我初步介绍了如何如何开发一个VSTO程序,在本文中,我将进一步深入介绍Word的插件开发.Word是一个大家在日常工作中一直接触的文档工 ...
- yii分页
关于分页有一个重要的类CPagination. CPagination represents information relevant to pagination. http://www.yiifra ...
- curl post传递json数据
有时想在命令行使用post http提交一个表单,比较常用的是POST模式和GET模式 GET模式什么option都不用,只需要把变量写在url里面就可以了 比如:curl http://www.wa ...
- RR区间锁 不是唯一索引,即使区间内没值,也锁
+--------- +---------------------------------------------------------------------------------------- ...
- Sublime Text 3 配置
配置: { "font_face": "Source Code Pro", , "highlight_line": true, " ...