问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

your bluetooth search model is这个是蓝牙搜索的意思吗

发布网友 发布时间:2023-01-06 17:22

我来回答

2个回答

热心网友 时间:2023-10-18 21:11

接上篇打开蓝牙继续,来一起看下蓝牙搜索的流程,触发蓝牙搜索的条件形式上有两种,一是在蓝牙设置界面开启蓝牙会直接开始搜索,另一个是先打开蓝牙开关在进入蓝牙设置界面也会触发搜索,也可能还有其它触发方式,但最后都要来到BluetoothSettngs.java的startScanning(),我们分析的起点也从这里开始,起步代码如下
[cpp] view plaincopy
private void updateContent(int bluetoothState, boolean scanState) {
if (numberOfPairedDevices == 0) {
preferenceScreen.removePreference(mPairedDevicesCategory);
if (scanState == true) {
mActivityStarted = false;
startScanning();
} else<span style="font-family: Arial, Helvetica, sans-serif;"> ........</span>
}
private void startScanning() {
if (!mAvailableDevicesCategoryIsPresent) {
getPreferenceScreen().addPreference(mAvailableDevicesCategory);
}
mLocalAdapter.startScanning(true);
}

其实在这里蓝牙搜索和打开流程是结构上是一致的,利用LocalBluetoothAdapter.java过渡到BluetoothAdapter.java再跳转至AdapterService.java要稍微留意下的是在这个过渡中startScaning()方法变成了startDiscovery()方法,看下代码:packages/apps/Settings/src/com/android/settings/bluetooth/LocalBluetoothAdapter.java
[java] view plaincopy
void startScanning(boolean force) {
if (!mAdapter.isDiscovering()) {
if (!force) {
// Don't scan more than frequently than SCAN_EXPIRATION_MS,
// unless forced
if (mLastScan + SCAN_EXPIRATION_MS > System.currentTimeMillis()) {
return;
}
// If we are playing music, don't scan unless forced.
A2dpProfile a2dp = mProfileManager.getA2dpProfile();
if (a2dp != null && a2dp.isA2dpPlaying()) {
return;
}
}
//这里才是我们最关注的,前面*条件关注一下就行了
if (mAdapter.startDiscovery()) {
mLastScan = System.currentTimeMillis();
}
}
BluetoothAdapter.java的那一段,路径 /frameworks/base/core/java/android/bluetooth/BluetoothAdapter.java
[java] view plaincopy
public boolean startDiscovery() {
.............................
AdapterService service = getService();
if (service == null) return false;
return service.startDiscovery();
}
这个service代码写得很明白AdapterService,转了一圈从framework又回到packages了,
下面的代码路径自然是 :packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterService.java,
[java] view plaincopy
boolean startDiscovery() {
enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH ADMIN permission");

return startDiscoveryNative();
}
和打开蓝牙根本就是一个套路,上面的流程略过一小步,很简单的不写了,下面要怎么走,估计大家也都猜到了,JNI应该出场了,
路径:/packages/apps/Bluetooth/jni/com_android_bluetooth_btservice_AdapterService.cpp
[cpp] view plaincopy
static jboolean startDiscoveryNative(JNIEnv* env, jobject obj) {
ALOGV("%s:",__FUNCTION__);

jboolean result = JNI_FALSE;
if (!sBluetoothInterface) return result;

int ret = sBluetoothInterface->start_discovery();
result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
return result;
}
在下面要去哪?稍微要动下脑筋,不过我们在上一篇android -- 蓝牙 bluetooth (二) 打开蓝牙已经说过怎么找了,注意android.mk文件,先找头文件,再找对应的实现C文件代码。就是现在回顾下,蓝牙打开和搜索的代码流程我们都看了,跳转都是一个套路,settings界面发起,LocalBluetoothAdapter.java过渡,去framework的转转(BluetoothAdapter.java)后回到packages的AdapterService.java,再走JNI来的external。流程就是这样的,相信类似的功能跳转(比如蓝牙配对,关闭蓝牙,停止扫描这些)大家都应该熟悉了,后面再有类似的功能就写函数名一笔带过了,还有这里要注意的就是这个start_discovery()实现代码的寻找,留意mk文件就是了,不复杂。小结结束,继续看代码 路径:/external/bluetooth/bluedroid/btif/src/bluetooth.c
[cpp] view plaincopy
static int start_discovery(void)
{
/* sanity check */
if (interface_ready() == FALSE)
return BT_STATUS_NOT_READY;

return btif_dm_start_discovery();
}
下面代码直接跳转就可以找到,路径external/bluetooth/bluedroid/btif/src/btif_dm.c
这个代码有点多,不过里面的信息也很多,所以连注释也一起保留的贴出来了,蓝牙的搜索实现并没有像蓝牙打开那样交由vendor厂商实现,在这里已经写出来了,仔细看下那些#if和#else,都是一些查询条件的调置,#if (BLE_INCLUDED == TRUE) 这个应该就google为蓝牙4.0 LE作的准备了,也算是今年google I/O大会上宣布即将支持蓝牙4.0低能耗版一个佐证吧,对于代码里面那些字符串的含义看这里好了external/bluetooth/bluedroid/bta/include/bta_api.h,一个头文件,大部分字符串和结构体的定义都在这了,多少还有些注释。
[cpp] view plaincopy
bt_status_t btif_dm_start_discovery(void)
{
tBTA_DM_INQ inq_params;
tBTA_SERVICE_MASK services = 0;

BTIF_TRACE_EVENT1("%s", __FUNCTION__);
/* TODO: Do we need to handle multiple inquiries at the same time? */

/* Set inquiry params and call API */
#if (BLE_INCLUDED == TRUE)
inq_params.mode = BTA_DM_GENERAL_INQUIRY|BTA_BLE_GENERAL_INQUIRY;
#else
inq_params.mode = BTA_DM_GENERAL_INQUIRY;
#endif
inq_params.ration = BTIF_DM_DEFAULT_INQ_MAX_DURATION;

inq_params.max_resps = BTIF_DM_DEFAULT_INQ_MAX_RESULTS;
inq_params.report_p = TRUE;

inq_params.filter_type = BTA_DM_INQ_CLR;
/* TODO: Filter device by BDA needs to be implemented here */

/* Will be enabled to TRUE once inquiry busy level has been received */
btif_dm_inquiry_in_progress = FALSE;
/* find nearby devices */
BTA_DmSearch(&inq_params, services, bte_search_devices_evt);

return BT_STATUS_SUCCESS;
}

BTA_DmSearch()方法是看起来是要搜索了,不过里面这个家伙bte_search_devices_evt才是真正干活的主力,所以我们先看它,在这个函数里
[cpp] view plaincopy
static void bte_search_devices_evt(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH *p_data) {
UINT16 param_len = 0;

if (p_data)
param_len += sizeof(tBTA_DM_SEARCH);
/* Allocate buffer to hold the pointers (deep copy). The pointers will point to the end of the tBTA_DM_SEARCH */
switch (event)
{
case BTA_DM_INQ_RES_EVT:
{
if (p_data->inq_res.p_eir)
param_len += HCI_EXT_INQ_RESPONSE_LEN;
}
break;
..............................
}
BTIF_TRACE_DEBUG3("%s event=%s param_len=%d", __FUNCTION__, mp_dm_search_event(event), param_len);

/* if remote name is available in EIR, set teh flag so that stack doesnt trigger RNR */
if (event == BTA_DM_INQ_RES_EVT)
p_data->inq_res.remt_name_not_required = check_eir_remote_name(p_data, NULL, NULL);

btif_transfer_context (btif_dm_search_devices_evt , (UINT16) event, (void *)p_data, param_len,
(param_len > sizeof(tBTA_DM_SEARCH)) ? search_devices_copy_cb : NULL);
}
在上面的这个函数里又有这个bte_search_devices_evt,在它里我们能看一个 HAL_CBACK,这是要往回发消息了,看下这个函数的全貌,说是全貌,不过还是只贴出一个case分支,太长了,大家还是自行还源码吧。到这里已经可以知道扫描到蓝牙设备的mac地址和设备名,那个bdcpy函数就是在解析mac地址,有了这些,蓝牙搜索是到应该在界面展示成果的时候了,开始回调,忘记代码路径了,这个函数都在这个文件里: /external/bluetooth/bluedroid/btif/src/btif_dm.c
[cpp] view plaincopy
static void btif_dm_search_devices_evt (UINT16 event, char *p_param)

tBTA_DM_SEARCH *p_search_data;
BTIF_TRACE_EVENT2("%s event=%s", __FUNCTION__, mp_dm_search_event(event));

switch (event)
{
case BTA_DM_DISC_RES_EVT:
{
p_search_data = (tBTA_DM_SEARCH *)p_param;
/* Remote name update */
if (strlen((const char *) p_search_data->disc_res.bd_name))
{
bt_property_t properties[1];
bt_bdaddr_t bdaddr;
bt_status_t status;

properties[0].type = BT_PROPERTY_BDNAME;
properties[0].val = p_search_data->disc_res.bd_name;
properties[0].len = strlen((char *)p_search_data->disc_res.bd_name);
bdcpy(bdaddr.address, p_search_data->disc_res.bd_addr);

status = btif_storage_set_remote_device_property(&bdaddr, &properties[0]);
ASSERTC(status == BT_STATUS_SUCCESS, "failed to save remote device property", status);
HAL_CBACK(bt_hal_cbacks, remote_device_properties_cb,
status, &bdaddr, 1, properties);
}
/* TODO: Services? */
}
break;
一小段log,下面的文字就在上面的函数里打出来的,即便上面的写的函数没有,肯定也在附近了。
05-30 13:52:14.890 1578 2612 D bt-btif : bte_search_devices_evt event=BTA_DM_INQ_RES_EVT param_len=524
05-30 13:52:14.890 1578 2612 D bt-btif : search_devices_copy_cb: event=BTA_DM_INQ_RES_EVT
05-30 13:52:14.890 1578 2584 I bt-btif : btif_dm_search_devices_evt event=BTA_DM_INQ_RES_EVT
05-30 13:52:14.890 1578 2584 D bt-btif : btif_dm_search_devices_evt() ec:89:f5:ba:fb:03 device_type = 0x1

当然回过头我们还要看下那个BTA_DmSearch(),看它的实现,更应该是起消息发送的作用,代码在/external/bluetooth/bluedroid/bta/dm/bta_dm_api.c,这个函数具体流程并没有看多少,当工具方法看了,有时间看看还是没坏处的。
[cpp] view plaincopy
void BTA_DmSearch(tBTA_DM_INQ *p_dm_inq, tBTA_SERVICE_MASK services, tBTA_DM_SEARCH_CBACK *p_cback)
{ tBTA_DM_API_SEARCH *p_msg;
if ((p_msg = (tBTA_DM_API_SEARCH *) GKI_getbuf(sizeof(tBTA_DM_API_SEARCH))) != NULL)
{
memset(p_msg, 0, sizeof(tBTA_DM_API_SEARCH));

p_msg->hdr.event = BTA_DM_API_SEARCH_EVT;
memcpy(&p_msg->inq_params, p_dm_inq, sizeof(tBTA_DM_INQ));
p_msg->services = services;
p_msg->p_cback = p_cback;
p_msg->rs_res = BTA_DM_RS_NONE;
bta_sys_sendmsg(p_msg);
}
}
看了上面方法后我们 要回去了看看,代码通过JNI下来的,回去也是看JNI的回调方法
[cpp] view plaincopy
method_deviceFoundCallback = env->GetMethodID(jniCallbackClass, "deviceFoundCallback", "([B)V");
deviceFoundCallback方法最后会来java层的/packages/apps/Bluetooth/src/com/android/bluetooth/btservice/RemoteDevices.java
[java] view plaincopy
void deviceFoundCallback(byte[] address) {
// The device properties are already registered - we can send the intent
// now
BluetoothDevice device = getDevice(address);
debugLog("deviceFoundCallback: Remote Address is:" + device);
DeviceProperties deviceProp = getDeviceProperties(device);
if (deviceProp == null) {
errorLog("Device Properties is null for Device:" + device);
return;
}

Intent intent = new Intent(BluetoothDevice.ACTION_FOUND);
intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
intent.putExtra(BluetoothDevice.EXTRA_CLASS,
new BluetoothClass(Integer.valueOf(deviceProp.mBluetoothClass)));
intent.putExtra(BluetoothDevice.EXTRA_RSSI, deviceProp.mRssi);
intent.putExtra(BluetoothDevice.EXTRA_NAME, deviceProp.mName);

mAdapterService.sendBroadcast(intent, mAdapterService.BLUETOOTH_PERM);
}
到这里就是给界面发广播,应用层收到广播显示出来,通过这个handle,这个handle可以在BluetoothEventManager.java的构造函数里找到,
[java] view plaincopy
addHandler(BluetoothDevice.ACTION_FOUND, new DeviceFoundHandler());
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
BluetoothDevice device = intent
.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);

Handler handler = mHandlerMap.get(action);
if (handler != null) {
handler.onReceive(context, intent, device);
}
}
};
这里handle对应要看DeviceFoundHandler,也就是下面贴出来的代码,
[java] view plaincopy
private class DeviceFoundHandler implements Handler {
public void onReceive(Context context, Intent intent,
BluetoothDevice device) {
........................
// 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.
CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
if (cachedDevice == null) {
cachedDevice = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, device);
Log.d(TAG, "DeviceFoundHandler created new CachedBluetoothDevice: "
+ cachedDevice);
// callback to UI to create Preference for new device
dispatchDeviceAdded(cachedDevice);
}
......................
}
}
在if语句中dispatchDeviceAdded()向界面分发消息,最后处理消息的地方在这里,已经到settings应用里了
/packages/apps/Settings/src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java
[java] view plaincopy
public void onDeviceAdded(CachedBluetoothDevice cachedDevice) {
if (mDevicePreferenceMap.get(cachedDevice) != null) {
return;
}

// Prevent updates while the list shows one of the state messages
if (mLocalAdapter.getBluetoothState() != BluetoothAdapter.STATE_ON) return;

if (mFilter.matches(cachedDevice.getDevice())) {
createDevicePreference(cachedDevice);
}
}
上面代码中最后一个分支就是界面显示要做的事了,从settings界面开始再到settings界面显示出搜索到蓝牙结束,后面的代码不再写了,本文关心的东东到此结束。

热心网友 时间:2023-10-18 21:12

应该是的,不是的话追问
声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
苹果电脑电池充不进电苹果电脑充不进去电是怎么回事 苹果电脑不充电没反应苹果电脑充电指示灯不亮充不了电怎么办 狗狗更加忠诚护家、善解人意,养一只宠物陪伴自己,泰迪能长多大... 描写泰迪狗的外形和特点的句子 国外留学有用吗 花钱出国留学有用吗 !这叫什么号 百万医疗赔付后是否可以续保 前一年理赔过医疗险还能续保吗? 医疗住院险理赔后还能购买吗? 一叶障目告诉我们的道理 怎样哄好生气的男朋友(怎么哄生气的男朋友) 陈乔恩老公是谁叫什么? 男友点赞美女,陈乔恩搂腰贴脸男星明道是否是回击? 一叶障目给人启示 苍山落日明整首诗内容 京东移动端白条怎么使用有果果 世界文明的近义词语是什么? 怎么才能快速的开通呢 文明和著名是不是近义词 文明近义词是什么 骚扰电话14人标记过是什么意思 宝宝39度多烧一晚上有事吗 绑定手机号了,怎样取消绑定? 怎么取消绑定手机号 共享经济体制到底是好还是不好 12月底过年有免费过路费吗 2020年阳历年高速免费吗 过年那几天高速不收过路费 过路费什么时候免费 手机开数据流量为什么上不了网 学习一年级怎么造句 用学的造句(大约30个左右) 新西兰劳动力缺乏,*紧缺现象严重,可以介绍下护理硕士研究生如何吗? 护理专业是新西兰留学的好选择,能介绍一下新西兰护理专业吗? 怎麼才可以添加新浪微博的人数捏? 西梅用开水烫可以去皮吗 什么是随分子钱啊 苹果4s突然卡住了,按了锁屏键结婚黑屏了,电话打的通但是屏幕不亮。开关机键还坏了,怎么办? 2023年上半年教资面试考试时间 乌鲁木齐哪里可以学面点? 梦见计数、数数 梦见数数数不清 梦见别人数数 梦见孩子数数 梦见教小学生数数 定格作文1000字 液体沸点与气压关系并解释 电脑里面隐藏的东西怎么显示出来怎么办 比大众车高半个头大概是多高