在上一篇文章中,我们详细分析了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. windows API 统计系统字体

    最近工作中遇到一个需求,需要统计当前系统中包含的所有字体.在网上逛了一圈后发现了EnumFontFamiliesEx这个API好像就可以实现这个功能.这里将自己对这个API的理解做一个记录,算是对这块 ...

  2. linux 监控服务器脚本

    #!/bin/bash ctime=`date +%x%T`monitor_dir=/home/jk/if [ ! -d $monitor_dir ]; then    mkdir $monitor_ ...

  3. YZOI回忆录&&YZOI3.0介绍&&某些资源的分享

    “那段时光就像块透明的琉璃,美得那么虚幻.飘渺.可是它毕竟在我生命里闪现,哪怕如萤光一样微弱,却照亮了我整个心房.”1.前序伴随着yzoi2.0版本离我而去的是我半年的OI生涯,在这半年内我步入了一个 ...

  4. js中的潜伏者之Arguments对象

    argument 说明: 在JavaScript中,arguments是对象的一个特殊属性.arguments对象就像数组,但是它却不是数组.可以理解为他是潜伏者,通俗的说,就是你传的参数不一定按照参 ...

  5. [jQuery编程挑战]005 使用最短的代码生成元素的闪烁效果

    <!DOCTYPE html> <html lang="zh"> <head> <meta charset="utf-8&quo ...

  6. Linux on ASUS N550JK4700

    实际上,ASUS N550JK对Ubuntu 14.04的兼容性是相当好的,包括无线网卡.蓝牙.键盘背光的调节.触摸板的开关.音量的键盘调节都是安装后无需配置直接可以使用的,这是出乎意料的,因为这些功 ...

  7. 一次性安装src.rpm编译所依赖的软件包

    yum-builddep SRPMS/fcitx-4.2.8.4-4.1.cgdl21.src.rpm NAME       yum-builddep - install missing depend ...

  8. Python中几种数据结构的整理,列表、字典、元组、集合

    列表:shoplist = ['apple', 'mango', 'carrot', 'banana']字典:di = {'a':123,'b':'something'}集合:jihe = {'app ...

  9. intent.addFlags

     一.Activity和Task(栈)的关系 Task就像一个容器,而Activity就相当与填充这个容器的东西,第一个东西(Activity)则会处于最下面,最后添加的东西(Activity)则会在 ...

  10. Swift中KIF测试的特点-b

    我最近在忙着回归到过去测试代码的老路子,使用KIF和XCTest框架,这样会使得iOS中的测试变得简单.当我开始捣鼓KIF的时候,我用Swift写的应用出了点小问题,不过最终还是很机智的搞定了.在我写 ...