[置顶] [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 保留关键字
JavaScript 保留关键字 在 JavaScript 中,一些标识符是保留关键字,不能用作变量名或函数名. JavaScript 标准 所有的现代浏览器完全支持 ECMAScript 3(ES3 ...
- java_设计模式_外观模式_Facade Pattern(2016-08-09)
外观模式/门面模式 1.概念 为子系统中的一组接口提供一个统一接口.Facade模式定义了一个高层接口,这个接口使得这子系统更容易使用. 2.UML 由于外观模式的结构图过于抽象,因此把它稍稍具体点. ...
- slf4j与log4j
推荐使用SLF4J(Simple Logging Facade for Java)作为日志的api,SLF4J是一个用于日志系统的简单Facade,允许最终用户在部署其应用时使用其所希望的日志系统. ...
- Invalid project description overlaps the location of another project [android]
解决办法: 1.将工程放到其他目录下,然后执行Android工程的导入,导入时可以选择“Copy projects into workspace”: 2.不用Android工程导入,而用普通的工程导入 ...
- SGU 117.Counting
时间限制: 0.25 sec. 空间限制: 4096 KB 题目大意: 给你n,m,k(都小于10001),和 n 个数,求这n个数中有多少个数的m次幂能够整除k.(即 n i^m % k==0). ...
- IOS下双击背景, touchmove, 阻止页面背景scroll.
ios prevent dblclick(tap) page scrollhtml add:("minimal-ui" is very important) <meta na ...
- 计算机天才Aaron Swartz 名作 《如何提高效率》——纪念真正的“hacker"!
如何提高效率 <HOWTO: Be more productive>(如何提高效率)作者:Aaron Swartz 肯定有人跟你说过这样的话,“你有看电视的那么长时间,都可以用来写一本书了 ...
- Web控件
Web控件可分三类 HTML控件 html服务器控件是在HTML控件的基础上,额外增加了一个在当前页面唯一的ID属性值和一个runat = "server" 属性html服务器控件 ...
- MVC架构模式
MVC是一个框架模式,它强制性的使应用程序的输入.处理和输出分开.使用MVC应用程序被分成三个核心部件:模型.视图.控制器. V页面传递数据给C,C调用模型处理返回数据给V 最典型的MVC就是JSP ...
- 如何更好辨认House of hello恶搞包的真假
相信很多朋友都知道houseofhello恶搞包这个品牌,甚至很多朋友都买过,首先呢,她是恶搞包,算自主品牌,它无淘宝店,更没有所谓的香港实体店.因为这品牌受到广大朋友的狂热,导致无数仿品的出现,淘宝 ...