蓝牙HID——Android手机注册HID时出现 Could not bind to Bluetooth (HID Device) Service with Intent * 的问题分析
异常描述
在蓝牙HID的开发过程中,使用红米K30手机 MIUI12.5(Android 11) 系统,打算将手机打造成蓝牙外设(键盘、触摸板、游戏手柄等)。首先调用下面的方式与系统蓝牙HID服务绑定:
mBtAdapter.getProfileProxy(mContext, mServiceListener, BluetoothProfile.HID_DEVICE);
出现下面的错误信息
Could not bind to Bluetooth Service with Intent { act=android.bluetooth.IBluetoothHidDevice }
上述报错后就不会与系统蓝牙HID服务绑定,从而无法得到 BluetoothHidDevice
进行注册。而使用 BluetoothProfile.A2DP
绑定时则无此问题。
源码分析
方法 BluetoothAdapter.getProfileProxy()
的代码如下:
public boolean getProfileProxy(Context context, BluetoothProfile.ServiceListener listener,int profile) {if (context == null || listener == null) {return false;}if (profile == BluetoothProfile.HEADSET) {BluetoothHeadset headset = new BluetoothHeadset(context, listener, this);return true;} else if (profile == BluetoothProfile.A2DP) {...代码省略} else if (profile == BluetoothProfile.HID_DEVICE) {BluetoothHidDevice hidDevice = new BluetoothHidDevice(context, listener, this);return true;} else if (profile == BluetoothProfile.HEARING_AID) {...代码省略}
根据 BluetoothProfile.HID_DEVICE
创建 BluetoothHidDevice
,BluetoothHidDevice
构造函数中会调用 doBind()
与系统蓝牙应用的蓝牙HID服务进行绑定,在Android 9 源码如下:
/frameworks/base/core/java/android/bluetooth/BluetoothHidDevice.java
//BluetoothHidDevice.javaboolean doBind() {Intent intent = new Intent(IBluetoothHidDevice.class.getName());ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);intent.setComponent(comp);if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,mContext.getUser())) {Log.e(TAG, "Could not bind to Bluetooth HID Device Service with " + intent);return false;}Log.d(TAG, "Bound to HID Device Service");return true;}
以 android.bluetooth.IBluetoothHidDevice
作为 Action 与系统应用的蓝牙服务绑定。
Intent.resolveSystemService()
方法查看系统服务:
@UnsupportedAppUsagepublic @Nullable ComponentName resolveSystemService(@NonNull PackageManager pm,@PackageManager.ComponentInfoFlags int flags) {if (mComponent != null) {return mComponent;}List<ResolveInfo> results = pm.queryIntentServices(this, flags);if (results == null) {return null;}ComponentName comp = null;for (int i=0; i<results.size(); i++) {ResolveInfo ri = results.get(i);if ((ri.serviceInfo.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) == 0) {continue;}ComponentName foundComp = new ComponentName(ri.serviceInfo.applicationInfo.packageName,ri.serviceInfo.name);if (comp != null) {throw new IllegalStateException("Multiple system services handle " + this+ ": " + comp + ", " + foundComp);}comp = foundComp;}return comp;}
Intent.resolveSystemService()
的方法是系统用于解决系统应用程序服务意向的特殊功能。如果存在与Intent的多个潜在匹配,则引发异常。如果没有匹配项,则返回null。
查找不到 android.bluetooth.IBluetoothHidDevice
作为 Action的系统蓝牙HID服务将 ComponentName
为 null ,因此出现 “Could not bind to Bluetooth HID Device Service with Intent { act=android.bluetooth.IBluetoothHidDevice }” 的报错。
Android 10 不直接调用 doBind()
方法进行绑定,而是增加 BluetoothProfileConnector
进行绑定,源码如下:
/frameworks/base/core/java/android/bluetooth/BluetoothProfileConnector.java
//BluetoothProfileConnector.javaprivate boolean doBind() {synchronized (mConnection) {if (mService == null) {logDebug("Binding service...");try {Intent intent = new Intent(mServiceName);ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);intent.setComponent(comp);if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,UserHandle.CURRENT_OR_SELF)) {logError("Could not bind to Bluetooth Service with " + intent);return false;}} catch (SecurityException se) {logError("Failed to bind service. " + se);return false;}}}return true;}
Android 9 和 Android 10 的错误打印不一致,Android 9 为 “Could not bind to Bluetooth HID Device Service with”, 而 Android 10 以上为 "Could not bind to Bluetooth Service with "。
但不管哪个版本都是与系统蓝牙应用的HID服务进行绑定。
packages\apps\Bluetooth\src\com\android\bluetooth\hid\HidDeviceService.java
系统中找不到蓝牙服务、无法绑定、或者蓝牙应用异常同样也无法正常获取服务注册蓝牙HID。
判断设备是否支持蓝牙HID
根据上述 Intent.resolveSystemService()
的方法,第三方应用可以执行下面方法判断设备是否有蓝牙HID服务来,返回 true 代表支持第三方应用注册蓝牙HID,反之当前设备的系统不支持。
public boolean isSupportBluetoothHid() {Intent intent = new Intent("android.bluetooth.IBluetoothHidDevice");List<ResolveInfo> results = pm.queryIntentServices(intent, 0);if (results == null) {return false;}ComponentName comp = null;for (int i=0; i<results.size(); i++) {ResolveInfo ri = results.get(i);if ((ri.serviceInfo.applicationInfo.flags& ApplicationInfo.FLAG_SYSTEM) == 0) {continue;}ComponentName foundComp = new ComponentName(ri.serviceInfo.applicationInfo.packageName,ri.serviceInfo.name);if (comp != null) {throw new IllegalStateException("Multiple system services handle " + this+ ": " + comp + ", " + foundComp);}comp = foundComp;}return comp != null;}
解决方案
红米K30手机出现此问题可能是本身小米系统移植存在差异导致的,升级MIUI13(Android 12)后无此报错。
由于没有小米系统的源码,无法进行分析修改。只能尝试升级其他系统版本,根据上述 判断设备是否支持蓝牙HID 来识别当前系统的支持情况。
如果当前系统支持HID,那么通过调用 BluetoothHidDevice.registerApp()
方法 将回调 onAppStatusChanged()
状态 registered 为 true 时,如下:
onAppStatusChanged: pluggedDevice:null registered:true
这代表注册成功,通过另一个设备查找你的手机进行配对,需要调用 setScanMode
的模式让另一设备发现并连接,具体方式可查看另一篇博文 蓝牙HID——将android设备变成蓝牙键盘(BluetoothHidDevice)。配对成功后即可充当HID设备控制另一个终端设备。
在 Android 9 之前只有系统应用才可以注册 HID ,Android 9 之前的系统版本参考此篇博客 Android 蓝牙开发(三)蓝牙Hid 开发
蓝牙HID——Android手机注册HID时出现 Could not bind to Bluetooth (HID Device) Service with Intent * 的问题分析相关推荐
- android 添加通讯录联系人头像,Android 手机通讯录开发时给联系人添加头像失败的坑...
Android 手机通讯录开发时给联系人添加头像失败的坑,在给联系人添加头像代码 Bitmap photo = ...; // 将 Bitmap 转为 byte[] byte[] bytes = Ls ...
- android手机连接电脑时直接截屏到电脑
如题,android手机连接mac,直接快速截屏到mac. 解决方法: 利用android的adb命令即可: #截取手机屏幕保存到SDCard adb shell /system/bin/screen ...
- php推送手机,PHP_解析php做推送服务端实现ios消息推送,准备工作1.获取手机注册应用 - phpStudy...
解析php做推送服务端实现ios消息推送 准备工作1.获取手机注册应用的deviceToken(iphone手机注册应用时返回唯一值deviceToken) 2.获取ck.pem文件(做手机端的给) ...
- android恢复联系人,如何从Android手机恢复联系人[最佳方式]
有没有简单的方法 从Android设备恢复已删除/丢失的联系人? 各种原因将导致Android手机上的数据丢失. 例如,意外删除可能会导致电话号码丢失,而一些错误的操作也可能导致联系人丢失. 此外,技 ...
- Android手机的驱动安装
Android手机连接电脑时,一般情况下,电脑会自动搜索并安装相应的驱动,但如果自动搜索安装不成功,就需要我们手动来安装.以下是手动安装流程: 1.去手机官网下载对应机型的USB驱动,如有必要,进行解 ...
- chrome inspect联调android手机webview和web h5遇坑
adb unauthorized C:\Users\xxx.android里面删掉adbkey 和adbkey.pub两个文件,然后重新插拔手机 执行: adb kill-server adb sta ...
- android设备登录工行卡,工行Android手机银行怎么登陆?
工行Android手机银行首次登录步骤:您在Android主界面点击工行手机银行客户端图标,进入登录页面,输入手机号和登录密码,点击"登录"键. 非首次登录步骤:登录页面手机号输入 ...
- 买android手机,买Android手机理由:iPhone 6竟无言以对
如果用户在选购Android手机和iPhone时陷入两难境地,那么不妨考虑以下一些因素.以下7大理由表明,选择没那么困难,你应当选购Android手机而非iPhone. 1.Android手机与谷歌多 ...
- Android手机连接蓝牙播放时,蓝牙设备如何显示歌名、专辑、歌手等信息?
转眼间,在XX音乐(国内著名音乐APP公司)工作了1年多了,作为Android多媒体开发的主力,必须奉上一点知识了. 当这个问题客服反馈给我的时候,我一脸懵逼,面对各种前辈们留下的坑,我必须说,我一定 ...
最新文章
- 操作系统(十九)进程互斥的软件实现方法
- KMP模式串匹配+Compress Words CodeForces - 1200E
- pcf8523_PCF上的Spring Cloud合同和Spring Cloud Services
- php file_get_contents 效率,php 浅析file_get_contents、curl 的效率和稳定性
- 如何用20%精力搞定80%任务
- Microsoft Office Visio 2007 下载
- vue 登录页面背景 - 动态粒子特效包括vue3使用 (Vue-Particles)
- 综述 | 一文看尽三种针对人工智能系统的攻击技术及防御策略
- PMP项目管理专业人员资格认证
- 如何把自己打造成为一名金领架构师-基础篇(一)
- 记录一次修复知网学位论文目录下载油猴脚本的过程
- 【运筹学】模型速览及推荐学习视频
- java如何开发视频软件_使用JAVA编写视频播放器
- 【C++登山之路之初露锋芒 2】——内联函数+ 引用+auto+nullptr关键字(万字详解,图片演示,结构原理)
- swift代码转oc代码_什么是不安全的Swift代码?
- zabbix4.0配置钉钉机器人告警详细教程
- java+jna+DD实现全局键鼠驱动级模拟
- win7系统无法连接局域网服务器,win7系统无法访问局域网的解决步骤
- 加利福尼亚大学研究报告:让AI自我怀疑以防人类被颠覆
- SRGAN模型——pytorch实现
热门文章
- COM服务器应用程序本地激活权限错误解决方法
- 公司已经3个月发不出工资了。没有钱招不到人,老项目一堆烂摊子。
- Python(三)数字日期和时间
- 17-阿里云服务器ECS使用教程之Web环境的搭建
- 全面剖析redis分布式锁
- mybatis 报错There is no getter for property named 'XXX' in 'class com.xx.xx'
- web项目部署架构图
- cocos2dx3.3显示中文
- 计算机可以编程游戏吗,我的世界真正的大神,在游戏中编程,制作出能玩的单机游戏...
- 微信小程序商城搭建,微信小程序商城源码,微信小程序商城项目