[置顶] [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 ...
随机推荐
- 【转】jQuery教程
“jQuery风暴” 推荐及配套代码下载 ziqiu.zhang 2011-03-24 00:28 阅读:15339 评论:100 从零开始学习jQuery(剧场版) 你必须知道的javascri ...
- Getopt::Long 模块的简单使用
用法简介 1.带值参数传入程序内部 ※参数类型:整数, 浮点数, 字串 GetOptions( 'tag=s' => \$tag ); ‘=’表示此参数一定要有参数值, 若改用’:'代替表示参数 ...
- PHPCMS(2)PHPCMS V9 环境搭建(转)
转自:http://www.cnblogs.com/Braveliu/p/5072920.html PHPCMS V9的学习总结分为以下几点: [1]PHPCMS 简介 PHP原始为Personal ...
- Bootstrap_表单_表单控件
一.输入框input 单行输入框,常见的文本输入框,也就是input的type属性值为text. 在Bootstrap中使用input时也必须添加type类型,如果没有指定type类型,将无法得到正确 ...
- [HOWTO] Install Sphinx for A Script Pro
Hi, Here's a small howto on installing Sphinx Search (http://sphinxsearch.com/) and configuring it t ...
- text-decoration属性
一.在CSS1中,text-decoration有六个值: text-decoration:none //默认,定义标准的文本,没有任何样式,正常显示 text-decoration:underli ...
- 终端上设置git
http://blog.163.com/xianfuying@126/blog/static/21960005201181482518631/ 在-/.ssh的位置vi id_rsa.pub 拷贝的时 ...
- Highways
poj1751:http://poj.org/problem?id=1751 题意:给你n个城市,每个城市的坐标给你,然后为了是每个城市都连通,需要在已经建了一些街道额基础上,再次建一些街道使其连通, ...
- Oracle三组难缠的hint no_unnest/unnest,push_subq,push_pred--平展化(转)
经常有人把这三个hint搞混,主如果因为对三种重写道理不清楚.特总结如下.(实验景象为10204)1. no_unnest, unnestunnest我们称为对子查询展开,顾名思义,就是别让子查询孤单 ...
- svn图形客户端:smartsvn,svnmanager,rapidsvn,svnworkbench,rabbitsvn,Esvn, trac
svn图形客户端: smartsvn,http://www.oschina.net/p/smartsvn, 不用安装直接运行 qsvn, http://www.oschina.net/p/qsvn r ...