-->
原文网址:http://www.sychzs.cn/xubin341719/article/details/38584469
关键字:蓝牙blueZ A2DP、SINK、sink_connect、sink_disconnect、sink_suspend、sink_resume、sink_is_connected、sink_get_properties、AUDIO、DBUS
版本:基于android4.2 bluez之前的版本 内核:linux/ linux3.08
系统:android/android4.1.3.4
作者:xubin341719(欢迎转载,请注明作者,请尊重版权,谢谢)
欢迎指正错误,共同学习共同进步! !
参考网站:
http://www.sychzs.cn/u011960402/article/details/17216563
http://www.sychzs.cn/fityme/archive/2013/04/13/3019471 .html套接字相关
http://www.sychzs.cn/wwwkljoel/item/a35e5745d14e02e6bcf45170setsockopt
Android 蓝牙简介(一):基本概念和硬件接口
Android 蓝牙简介(二):Android 蓝牙代码架构及其 uart 转 rfcomm 流程
Android 蓝牙简介(三):蓝牙扫描(扫)设备分析
Android蓝牙简介(四):a2dp connect流程分析
1。蓝牙扫描常用的方法:
蓝牙扫描可以通过两种方式实现: 命令行 hciitool 扫描; Android界面触发,通过JNI和DUBS发出命令。 ?结果
2。 Android 界面触发,通过 JNI 和 DUBS 发出命令:通过 Android 界面点击搜索设备
2。内核层逻辑:
当然IOCTL只是其中之一。
idh.code\kernel\net\bluetooth\ hci_sock.c
- 静态 const struct proto_ops hci_sock_ops = {
- …………
- .ioctl = hci_sock_ioctl,
- .poll = datagram_poll,
- .listen = sock_no_listen,
- …………
- };
(1) 应用部分:
1。 idh.code\packages\apps\Settings\src\com\android\settings\bluetooth\www.sychzs.cn
- @覆盖
- public boolean onPreferenceTreeClick(PreferenceScreen首选项Screen,
- 偏好偏好){
- …………
- mLocalAdapter.startScanning(true);
- 返回true;
- }
2、 idh.code\packages\apps\Settings\src\com\android\settings\bluetooth\www.sychzs.cn
- 私有最终蓝牙适配器 mAdapter;
- void 开始扫描(布尔力) {
- //仅当我们尚未扫描时才开始
- if(!mAdapter.isDiscovering()){
- if(!强制){
- //扫描频率不要超过 SCAN_EXPIRATION_MS,
- //除非被迫
- if(mLastScan + SCAN_EXPIRATION_MS > System.currentTimeMillis()){
- 返回;
- }
- //如果我们正在播放音乐,除非被迫,否则不要扫描。
- A2dpProfile a2dp = mProfileManager.getA2dpProfile();
- if(a2dp!= null && a2dp.isA2dpPlaying()){
- 返回;
- }
- }
- if(mAdapter.startDiscovery()){
- mLastScan = System.currentTimeMillis();
- }
- }
- }
3、idh.code\frameworks\base\core\java\android\bluetooth\蓝牙适配器.java
- public boolean startDiscovery(){
- if (getState()!= STATE_ON) 返回 false;
- 尝试{
- 返回 mService.startDiscovery();
- } catch (RemoteException e) {Log.e(TAG,"", e);}
- 返回 false;
- }
4、JNI函数的调用idh.code\frameworks\base\core\java\android\server\www.sychzs.cn
- private native boolean startDiscoveryNative();//Native函数声明
- 公共类 BluetoothService 扩展了 IBluetooth.Stub {
- 私有静态最终字符串TAG =“蓝牙服务”;
- 私有静态最终布尔值 DBG = true;
- …………
- 公共同步布尔startDiscovery(){
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
- “需要 BLUETOOTH_ADMIN 权限”);
- if (!isEnabledInternal()) 返回 false;
- 返回startDiscoveryNative();
- }
- ………………
- }
(2) JNI 部分:
1。 android_server_BluetoothService.cpp中JNI函数对照表
idh.code\frameworks\base\core\jni\android_server_BluetoothService.cpp
- 静态 JNINativeMethod sMethods[] = {
- /* 姓名、签名、funcPtr */
- ………………
- {"startDiscoveryNative", "()Z", (void*)startDiscoveryNative},
- {"stopDiscoveryNative", "()Z", (void *)stopDiscoveryNative},
- …………
- }
2。对应Native功能的实现
有一个知识点DBUS,后面我们会单独讲解
idh.code\frameworks\base\core\jni\android_server_BluetoothService.cpp
- #define BLUEZ_DBUS_BASE_IFC“org.bluez”
- #define DBUS_ADAPTER_IFACE BLUEZ_DBUS_BASE_IFC ".Adapter"//其实DBUS_ADAPTER_IFACE也是org.bluez.Adapter
- static jboolean startDiscoveryNative(JNIEnv *env, jobject 对象) {
- ………………
- /* 编写命令 */
- msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC,
- get_adapter_path(env,对象),
- DBUS_ADAPTER_IFACE,“开始发现”);
- …………
- }
- 原生函数startDiscoveryNative对应于字符串StartDiscovery。
(3)、DBUS部分
1。 DBUS对应方法的实现与JNI部分类似,也是采用函数结构对应关系。
idh.code\external\bluetooth\bluez\src\adapter.c
- #define ADAPTER_INTERFACE "org.bluez.Adapter"
- 静态GDBusMethodTable适配器_方法[] = {
- ………………
- { "ReleaseSession", "", "", release_session },
- {“开始发现”,“”,“”,adapter_start_discovery },
- {“停止发现”,“”,“”,adapter_stop_discovery,
- G_DBUS_METHOD_FLAG_ASYNC},
- ………………
- }
字符
StartDiscovery对应于C中的实现函数adapter_start_discovery。
2。实现adapter_start_discovery
idh.code\external\bluetooth\bluez\src\adapter.c
- 静态 DBusMessage *adapter_start_discovery(DBusConnection *conn,
- DBusMessage *msg, void *数据)
- {
- …………
- err = start_discovery(适配器);
- if(错误<0&&错误!=-EINPROGRESS)
- 返回 btd_error_failed(msg, strerror(-err));
- 完成:
- req = create_session(适配器,conn,msg,0,
- session_owner_exit);
- 适配器->disc_sessions = g_slist_append(适配器->disc_sessions, req);
- 返回 dbus_message_new_method_return(msg);
- }
3、start_discovery调用
idh.code\external\bluetooth\bluez\src\adapter.c
- const struct btd_adapter_ops *adapter_ops = NULL;
- static int start_discovery(struct btd_adapter *适配器)
- {
- …………
- pending_remote_name_cancel(适配器);
- 返回adapter_ops->start_discovery(adapter->dev_id);
- }
adapter_ops对应结构体btd_adapter_ops中的对应函数,如下: 以上部分对应btd_adapter_ops中的hci_ops结构体。
4。 btd_adapter_ops 中的 hci_ops 结构
idh.code\external\bluetooth\bluez\plugins\hciops.c
- 静态结构 btd_adapter_ops hci_ops = {
- …………
- .set_powered = hciops_set_powered,
- .set_discoverable = hciops_set_discoverable,
- .set_pairable = hciops_set_pairable,
- .set_limited_discoverable = hciops_set_limited_discoverable,
- .start_discovery = hciops_start_discovery,
- .stop_discovery = hciops_stop_discovery,
- ………………
- .create_bonding = hciops_create_bonding,
- .cancel_bonding = hciops_cancel_bonding,
- .read_local_oob_data = hciops_read_local_oob_data,
- .add_remote_oob_data = hciops_add_remote_oob_data,
- .remove_remote_oob_data = hciops_remove_remote_oob_data,
- .set_link_timeout = hciops_set_link_timeout,
- .retry_authentication = hciops_retry_authentication,
- };
5、hciops_start_discovery函数的实现
idh.code\external\bluetooth\bluez\plugins\hciops.c
- 静态int hciops_start_discovery(int索引)
- {
- int adapter_type = get_adapter_type(索引);
- 开关(适配器类型){
- 案例 BR_EDR_LE:
- 返回 hciops_start_inquiry(index, LENGTH_BR_LE_INQ);
- case BR_EDR: //蓝牙芯片为2.1+EDR的
- 返回 hciops_start_inquiry(index, LENGTH_BR_INQ);
- 案例 LE_ONLY:
- 返回 hciops_start_scanning(index, TIMEOUT_LE_SCAN);
- 默认:
- 返回-EINVAL;
- }
- }
6、hciops_start_inquiry
idh.code\external\bluetooth\bluez\plugins\hciops.c
- 静态int hciops_start_inquiry(int索引,uint8_t长度)
- {
- struct dev_info *dev = &devs[索引];
- uint8_t lap[3] = { 0x33, 0x8b, 0x9e};
- inquiry_cp inq_cp;
- DBG("hci%d长度%u",索引,长度);
- memset(&inq_cp, 0, sizeof(inq_cp));
- memcpy(&inq_cp.lap, lap, 3);
- inq_cp.length=长度;
- inq_cp.num_rsp = 0x00;
- if(hci_send_cmd(dev->sk,OGF_LINK_CTL,
)
- OCF_INQUIRY、INQUIRY_CP_SIZE、&inq_cp) < 0)
- 返回-errno;
- 返回0;
- }
7、idh.code\external\bluetooth\bluez\lib\hci.c
- /* 需要开放设备的 HCI 功能
- * dd - 由 hci_open_dev 返回的设备描述符。 */
- dd = 套接字(AF_BLUETOOTH、SOCK_RAW、BTPROTO_HCI);
- int hci_send_cmd(int dd,uint16_t ogf,uint16_t ocf,uint8_t plen,void *param)
- {
- ………………
- if(全){
- iv[2].iov_base = param;
- iv[2].iov_len = plen;
- ivn = 3;
- }
- while (writev(dd, iv, ivn) < 0) {//writev这里把数据写入到socket里面。
- if (errno == EAGAIN || errno == EINTR)
- 继续;
- 返回-1;
- }
- 返回0;
- }
(4) 内核部分:
1。 HCI FILTER 设置
HCIsocket 的类型为 BTPROTO_HCI。当上层调用setsockopt时,会触发内核的hci_sock_setsockopt函数的执行。这里设置了socket的过滤特性,包括数据包类型,也包括事件类型;
当上层调用setsockopt(sock, SOL_HCI, HCI_FILTER,&flt, sizeof(flt))时,触发对应的内核路径。
idh.code\kernel\net\bluetooth\hci_sock.c
- 静态 const struct proto_ops hci_sock_ops = {
- .family = PF_BLUETOOTH,
- .owner = THIS_MODULE,
- …………
- .shutdown = sock_no_shutdown,
- .setsockopt = hci_sock_setsockopt,
- .getsockopt = hci_sock_getsockopt,
- .connect = sock_no_connect,
- …………
- };
idh.code\kernel\net\bluetooth\hci_sock.c
- static int hci_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int len)
- {
- ………………
- 案例 HCI_FILTER:
- {
- struct hci_filter *f = &hci_pi(sk)->filter;
- uf.type_mask = f->type_mask;
- uf.opcode = f->操作码;
- uf.event_mask[0] = *((u32 *) f->event_mask + 0);
- uf.event_mask[1] = *((u32 *) f->event_mask + 1);
- }
- ………………
- }
这部分内核数据比较统一。命令是通过hci_send_cmd发送出去的,HCI_FILTER这个地方的处理我还没看懂,稍后补充。
Writev函数通过socket写入数据,经过VFS层,调用内核空间的sendmsg函数。
(5), EVENT 返回状态
控制器收到查询命令后,返回命令状态
1,cmd_status
idh.code\external\bluetooth\bluez\plugins\hciops.c
- 开关(eh->evt){
- 案例 EVT_CMD_STATUS:
- cmd_status(index, ptr);
- 断裂;
- 静态内联 void cmd_status(int index, void *ptr)
- {
- evt_cmd_status *evt = ptr;
- uint16_t 操作码 = btohs(evt->操作码);
- if (opcode == cmd_opcode_pack(OGF_LINK_CTL, OCF_INQUIRY))//如果是查询,则做特殊处理;
- cs_inquiry_evt(索引, evt->状态);
- }
2。 cs_inquiry_evt 的实现idh.code\external\bluetooth\bluez\plugins\hciops.c
- 静态内联void cs_inquiry_evt(int索引,uint8_t状态)
- {
- if (状态){//错误信息
- 错误(“查询失败,状态为0x%02x”,status);
- 返回;
- }
- set_state(index, DISCOV_INQ);//设置状态为INQ,并用发现属性变化回复上层
- }
3。设置不同的 DISCOV 状态 idh.code\external\bluetooth\bluez\plugins\hciops.c
- static void set_state(int索引,int状态)
- {
- ………………
- 开关(dev->discov_state){
- case DISCOV_HALTED://停止发现;
- if(adapter_get_state(适配器)== STATE_SUSPENDED)
- 返回;
- if(is_resolvname_enabled()&&
- adapter_has_discov_sessions(适配器))
- adapter_set_state(适配器,STATE_RESOLVNAME);
- 否则
- adapter_set_state(适配器,STATE_IDLE);
- 断裂;
- 案例DISCOV_INQ:
- 案例DISCOV_SCAN://扫描发现;
- adapter_set_state(适配器,STATE_DISCOV);
- 断裂;
- }
- }
4、设置适配器的状态idh.code\external\bluetooth\bluez\src\adapter.c
- idh.code\external\bluetooth\bluez\src\adapter.c
- #define ADAPTER_INTERFACE “org.bluez.Adapter”
- void adapter_set_state(struct btd_adapter *适配器,int状态)
- {
- …………
- 案例 STATE_DISCOV:
- discov_active = TRUE;
- //向上层回复发现属性变化
- emit_property_changed(连接,路径,
- ADAPTER_INTERFACE,“发现”,
- DBUS_TYPE_BOOLEAN,&discov_active);
- 断裂;
- …………
- }
emit_property_changed 发送PropertyChanged消息,消息内容为Discovering。通知上层BluetoothEventLoop进行Discovery。
5。 emit_property_changed发送Discovery消息的实现idh.code\external\bluetooth\bluez\src\dbus-common.c
这部分涉及到DBUS内容
- dbus_bool_t eager_property_changed(DBusConnection *conn,
- const char *路径,
- const char *接口,
- const char *名称,
- int类型,void *值)
- {
- DBusMessage *信号;
- DBusMessageIter iter;
- signal = dbus_message_new_signal(路径, 接口, "PropertyChanged"); // 创建消息对象并标识路径
- if(!信号){
- 错误(“无法分配新的%s.PropertyChanged信号”,
- 接口);
- 返回FALSE;
- }
- dbus_message_iter_init_append(signal, &iter);//按signal对应的参数
- dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name);//申请一个首地址,将之前推送的参数传入这个首地址
- append_variant(&iter, type, value);//
- return g_dbus_send_message(conn, signal);//开始发送呼叫并释放发送相关消息信息
- }
6。 DBUS消息接收的实现 idh.code\frameworks\base\core\jni\android_server_BluetoothEventLoop.cpp
- //WaitForAndDispatchEventNative()期间由dbus调用
- 静态 DBusHandlerResult event_filter(DBusConnection *conn, DBusMessage *msg,
- 无效*数据){
- …………
- else if (dbus_message_is_signal(msg, "org.bluez.Adapter", "PropertyChanged")) {
- jobobjectArray str_array = parse_adapter_property_change(env, msg);//(1)、接收消息分析
- if (str_array != NULL) {
- /* 检查蓝牙是否已(重新)启动,如果是则更新路径。 */
- jstring 属性 =(jstring) env->GetObjectArrayElement(str_array, 0);
- const char *c_property = env->GetStringUTFChars(property, NULL);
- if (!strncmp(c_property, "Powered", strlen("Powered"))) {
- jstring值=
- (jstring) env->GetObjectArrayElement(str_array, 1);
- const char *c_value = env->GetStringUTFChars(value, NULL);
- if(!strncmp(c_value,“true”,strlen(“true”)))
- nat->适配器= get_adapter_path(nat->conn);
- env->ReleaseStringUTFChars(value, c_value);
- }
- env->ReleaseStringUTFChars(property, c_property);
- env->CallVoidMethod(nat->me,
- method_onPropertyChanged,//(2)、
- method_onPropertyChanged NATVIE函数的实现
- str_array);
- } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
- goto success;
- }
(1)、对收到消息的解析 idh.code\frameworks\base\core\jni\android_bluetooth_common.cpp
- jobjectArray parse_adapter_property_change(JNIEnv *env, DBusMessage *msg) {
- return parse_property_change(env, msg, (Properties *) &adapter_properties,
- sizeof(adapter_properties) / sizeof(Properties));
- }
针对org.bluez.Adapter不同的消息类型
idh.code\frameworks\base\core\jni\android_bluetooth_common.cpp
- static Properties adapter_properties[] = {
- {"Address", DBUS_TYPE_STRING},
- {"Name", DBUS_TYPE_STRING},
- {"Class", DBUS_TYPE_UINT32},
- {"Powered", DBUS_TYPE_BOOLEAN},
- {"Discoverable", DBUS_TYPE_BOOLEAN},
- {"DiscoverableTimeout", DBUS_TYPE_UINT32},
- {"Pairable", DBUS_TYPE_BOOLEAN},
- {"PairableTimeout", DBUS_TYPE_UINT32},
- {"Discovering", DBUS_TYPE_BOOLEAN},
- {"Devices", DBUS_TYPE_ARRAY},
- {"UUIDs", DBUS_TYPE_ARRAY},
- };
(2)、method_onPropertyChanged NATVIE函数的实现 idh.code\frameworks\base\core\jni\android_server_BluetoothEventLoop.cpp
- static void classInitNative(JNIEnv* env, jclass clazz) {
- ALOGV("%s", __FUNCTION__);
- #ifdef HAVE_BLUETOOTH
- method_onPropertyChanged = env->GetMethodID(clazz, "onPropertyChanged",
- "([Ljava/lang/String;)V");
- method_onDevicePropertyChanged = env->GetMethodID(clazz,
- "onDevicePropertyChanged","(Ljava/lang/String;[Ljava/lang/String;)V");
- …………
- }
7、JNI调用onPropertyChanged对应JAVA的实现,在www.sychzs.cn
idh.code\frameworks\base\core\java\android\server\www.sychzs.cn中
private static native void classInitNative();
/*package*/ void onPropertyChanged(String[] propValues) {
………………
log("Property Changed: " + propValues[0] + " : " + propValues[1]);
String name = propValues[0];
if (name.equals("Name")) {//获取蓝牙名字;
…………
} else if (name.equals("Pairable") || name.equals("Discoverable")) {//配对;
………………
} else if (name.equals("Discovering")) {//扫描查询;
Intent intent;
adapterProperties.setProperty(name, propValues[1]);
if (propValues[1].equals("true")) {
intent = new Intent(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
} else {
// Stop the discovery.
mBluetoothService.cancelDiscovery();
intent = new Intent(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
}
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
} else if (name.equals("Devices") || name.equals("UUIDs")) {//Devices、UUID的获取;
………………
} else if (name.equals("Powered")) {//蓝牙打开、关闭;
mBluetoothState.sendMessage(BluetoothAdapterStateMachine.POWER_STATE_CHANGED,
propValues[1].equals("true") ? new Boolean(true) : new Boolean(false));
} else if (name.equals("DiscoverableTimeout")) {
adapterProperties.setProperty(name, propValues[1]);
}
}
(1)、看到这份log我们也许会更明白其他功能的由来:
- D BluetoothEventLoop: Property Changed: Powered : true
- D BluetoothEventLoop: Property Changed: Pairable : true
- D BluetoothEventLoop: Property Changed: Class : 5898764
- D BluetoothEventLoop: Property Changed: Pairable : true
- D BluetoothEventLoop: Property Changed: Discoverable : false
- D BluetoothEventLoop: Property Changed: Discovering : true
- D BluetoothEventLoop: Property Changed: Discovering : false
- D BluetoothEventLoop: Property Changed: Devices : 1
- D BluetoothEventLoop: Device property changed: 94:20:53:01:15:90 property: Connected value: true
- D BluetoothEventLoop: Device property changed: 94:20:53:01:15:90 property: Paired value: true
- D BluetoothEventLoop: Device property changed: 94:20:53:01:15:90 property: UUIDs value: 4
(2)、下面我们重点分析Discovering这部分:
idh.code\frameworks\base\core\java\android\server\www.sychzs.cn
- else if (name.equals("Discovering")) {
- Intent intent;
- adapterProperties.setProperty(name, propValues[1]);
- if (propValues[1].equals("true")) {//开始扫描
- intent = new Intent(BluetoothAdapter.ACTION_DISCOVERY_STARTED);//
- } else {
- // Stop the discovery. //停止扫描
- mBluetoothService.cancelDiscovery();
- intent = new Intent(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
- }
- mContext.sendBroadcast(intent, BLUETOOTH_PERM);
- }
- 这样就可以通过broadcast发送ACTION_DISCOVERY_STARTED广播,注册的receiver来响应了。
8、ACTION_DISCOVERY_STARTED\ACTION_DISCOVERY_FINISHED的receiver分析
从代码中我们可以看到这个action一共有两个receiver,一个是静态注册的BluetoothDiscoveryReceiver,一个是动态注册是ScanningStateChangedHandler。
(1)、BluetoothDiscoveryReceiver:这个receiver是在settings中的Androidmanifest中静态注册的。用途:主要用于获取扫描开始和终止的时间。
idh.code\packages\apps\Settings\AndroidManifest.xml
-
- android:name=".bluetooth.BluetoothDiscoveryReceiver">
1)、ACTION_DISCOVERY_STARTED、ACTION_DISCOVERY_FINISHED和AndroidManifest.xml文件的联系
idh.code\frameworks\base\core\java\android\bluetooth\www.sychzs.cn
- public final class BluetoothAdapter {
- private static final String TAG = "BluetoothAdapter";
- private static final boolean DBG = false;
- …………
- public static final String ACTION_DISCOVERY_STARTED =
- "android.bluetooth.adapter.action.DISCOVERY_STARTED";
- public static final String ACTION_DISCOVERY_FINISHED =
- "android.bluetooth.adapter.action.DISCOVERY_FINISHED";
- …………
- }
2)、BluetoothAdapter,蓝牙适配器,直到我们建立bluetoothSocket连接之前,都要不断操作它。
BluetoothAdapter中的动作常量
ACTION_DISCOVERY_FINISHED
|
已完成蓝牙搜索
|
ACTION_DISCOVERY_STARTED
|
已经开始搜索蓝牙设备
|
ACTION_LOCAL_NAME_CHANGED
|
更改蓝牙的名字
|
ACTION_REQUEST_DISCOVERABLE
|
请求能够被搜索
|
ACTION_REQUEST_ENABLE
|
请求启动蓝牙
|
ACTION_SCAN_MODE_CHANGED
|
扫描模式已经改变
|
ACTION_STATE_CHANGED
|
状态已改变
|
ACTION_CONNECTION_STATE_CHANGED
|
|
3)、收到广播后函数实现,开始扫描
Main log中显示的log为DISCOVERY_STARTED
D BluetoothDiscoveryReceiver: Received:android.bluetooth.adapter.action.DISCOVERY_STARTED
HCI log 中:
idh.code\packages\apps\Settings\src\com\android\settings\bluetooth\www.sychzs.cn这个文件中就一个函数,还是比简单
- public final class BluetoothDiscoveryReceiver extends BroadcastReceiver {
- private static final String TAG = "BluetoothDiscoveryReceiver";
- private static final boolean DEBUG = Debug.isDebug();
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (DEBUG) Log.d(TAG, "Received: " + action);
- if (action.equals(BluetoothAdapter.ACTION_DISCOVERY_STARTED) ||
- action.equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) {
- //共享时间戳,扫描开始和结束的时间。
- LocalBluetoothPreferences.persistDiscoveringTimestamp(context);
- }
- }
- }
ScanningStateChangedHandler的注册及用途,要用于开始扫描,和扫描显示界面的控制。
这个receiver是在idh.code\packages\apps\Settings\src\com\android\settings\bluetooth\www.sychzs.cn动态注册的,如下:
- BluetoothEventManager(LocalBluetoothAdapter adapter,
- CachedBluetoothDeviceManager deviceManager, Context context) {
- mLocalAdapter = adapter;
- …………
- // Bluetooth on/off broadcasts
- addHandler(BluetoothAdapter.ACTION_STATE_CHANGED, new AdapterStateChangedHandler());
- // Discovery broadcastsaddHandler(BluetoothAdapter.ACTION_DISCOVERY_STARTED, new ScanningStateChangedHandler(true));
- addHandler(BluetoothAdapter.ACTION_DISCOVERY_FINISHED, new ScanningStateChangedHandler(false));
- …………
- }
(1)、ScanningStateChangedHandler函数实现如下:idh.code\packages\apps\Settings\src\com\android\settings\bluetooth\www.sychzs.cn
- private class ScanningStateChangedHandler implements Handler {
- private final boolean mStarted;
- ScanningStateChangedHandler(boolean started) {
- mStarted = started;
- }
- public void onReceive(Context context, Intent intent,
- BluetoothDevice device) {
- synchronized (mCallbacks) {//1)、调用注册的callback
- 中的onScanningStateChanged函数。
- for (BluetoothCallback callback : mCallbacks) {
- callback.onScanningStateChanged(mStarted);
- }
- }
- //2)、这个函数就是把上次扫描到设备、和之前的设备做相应处理;
- mDeviceManager.onScanningStateChanged(mStarted);
- LocalBluetoothPreferences.persistDiscoveringTimestamp(context);
- }
- }
1)、调用注册的callback中的callback.onScanningStateChanged(mStarted)函数。
idh.code\packages\apps\Settings\src\com\android\settings\bluetooth\www.sychzs.cn
- public void onScanningStateChanged(boolean started) {
- if (started == false) {//《1》、如果扫描结束;
- removeOutOfRangeDevices();
- }
- updateProgressUi(started);// 《2》、UI显示小圆圈扫描;
《1》、如果扫描结束;removeOutOfRangeDevices();
idh.code\packages\apps\Settings\src\com\android\settings\bluetooth\www.sychzs.cn
- private void removeOutOfRangeDevices() {
- Collection cachedDevices =
- mLocalManager.getCachedDeviceManager().getCachedDevicesCopy();
- for (CachedBluetoothDevice cachedDevice : cachedDevices) {
- if (cachedDevice.getBondState() == www.sychzs.cn_NONE &&
- cachedDevice.isVisible() == false) {
- BluetoothDevicePreference preference = mDevicePreferenceMap.get(cachedDevice);
- if (preference != null) {
- mDeviceListGroup.removePreference(preference);
- }
- mDevicePreferenceMap.remove(cachedDevice);
- }
- }
- }
《2》、UI显示小圆圈扫描,updateProgressUi(started);如下图所示:
idh.code\packages\apps\Settings\src\com\android\settings\bluetooth\www.sychzs.cn
- private void updateProgressUi(boolean start) {
- if (mDeviceListGroup instanceof ProgressCategory) {
- ((ProgressCategory) mDeviceListGroup).setProgress(start);
- }
- }
2)、这部分的作用,开始扫描,不显示列表中内容,或把之前列表中没扫描到的设备清除
mDeviceManager.onScanningStateChanged(mStarted);
idh.code\packages\apps\Settings\src\com\android\settings\bluetooth\www.sychzs.cn
- private void updateProgressUi(boolean start) {
- if (mDeviceListGroup instanceof ProgressCategory) {
- ((ProgressCategory) mDeviceListGroup).setProgress(start);
- }
- }
- 2)、这部分的作用,开始扫描,不显示列表中内容,或把之前列表中没扫描到的设备清除
- mDeviceManager.onScanningStateChanged(mStarted);
- idh.code\packages\apps\Settings\src\com\android\settings\bluetooth\ www.sychzs.cn
- public synchronized void onScanningStateChanged(boolean started) {
- // If starting a new scan, clear old visibility
- // Iterate in reverse order since devices may be removed.
- //如果开始新的扫描,清除旧的能见设备,迭代反序因为有的设备可能被删除
- for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
- CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
- if (started) {//如果扫描开始就不显示;
- cachedDevice.setVisible(false);
- } else {//对扫描的结果作出判断,如果之前扫描过,这次没有扫描到,就移除列表。
- if (cachedDevice.getBondState() == www.sychzs.cn_NONE &&
- cachedDevice.isVisible() == false) {
- mCachedDevices.remove(cachedDevice);
- }
- }
- }
- }
-->