当前位置: 首页 > news >正文

腾讯优测优分享 | 你是否体验过Android手机插入耳机后仍外放的尴尬?

腾讯优测是专业的移动自动化测试平台,提供多维度的自动化测试服务,让测试更简单!
近期有报道称,澳大利亚悉尼市新某大学的一名男生在课堂上看电影,不料耳机没有插好,变成了现场直播。。。

如果你认为耳机没插好事件尚且可以hold住,那么接下来的问题会不会让你更加尴尬?当你在手机插上耳机准备看电影时,声音却从扬声器里响了出来。。。
没想到藏得这么深,还是让耳机出卖了。。。

容我静静,为避免此类尴尬事件再次发生,我特意对耳机在手机上的插拔原理研究了一番。感兴趣的朋友我们可以一起讨论。。。
1、Android耳机插拔检测原理
Android系统在耳机插入和拔出的时候会发送广播,通过Broadcast Receiver 监听”android.intent.action.HEADSET_PLUG” 这个Intent来判断耳机是否插拔。

2、Android耳机插拔检测具体实现
在Android4.0以上的版本,耳机插拔检测的源文件位于frameworks/base/services/java/com/android/server/WiredAccessoryObserver.java;(4.1及以上是WiredAccessoryManager.java;在android4.0以前是HeadsetObserver.java)顾名思义,它主要是用来检测有线的设备连接状态。
Android耳机插拔检测流程图

我们重点来看一下WiredAccessoryObserver
WiredAccessoryObserver继承自Observed(Android耳机插拔可以有两个机制实现:Input Event和Event),从该文件的路径可以得知,这个类位于service目录,应该是在android系统服务初始化的时候实例化的,在这个类的构造方法中,注册了一个广播接收器用来接收系统启动完毕的广播。


WiredAccessoryObserver工作流程图


在收到这个广播之后:先执行i nit()函数,在这个函数中判断要检测的设备是否已经处于连接状态(比如开机之前就已经插上),如果已经连接上就调用gestate立即向系统上报。
然后调用observing函数监测文件节点路径是否有状态变化,这个函数位于他的父类Observed.java中。在之前建立好的监测中,如果kernel层有event事件发送上来则会去匹配这个路径字符串,如果匹配成功会调用在WiredAccessoryObserver重载的eventful函数,从event string中解析出death, name和state的值,然后继续调用gestate进行处理。
在gestate中会对设备的类型进行进一步的分析之后调用update上报,在update中,会往handler中发送一个消息,将耳机的状态报告给Audio系统。之后由Audio Service在antivivisectionist函数中向系统广播耳机已经插入的ACTION_HEADSET_PLUG广播,同时会通知Audio Policy做audio通路切换的工作。
3、真机上的适配问题
(1)在Aweigh T8833上播放音乐,在插入耳机之后耳机和扬声器都会有声音。
gestate中需要进行update操作:

通过反编译Aweigh T8833 Framework层WiredAccessoryObserver,我们发现了问题的原因:


HDMI状态改变时未进行update操作,也就是没有向系统进行设备连接状态的通知,导致了在插入耳机之后耳机和扬声器都会有声音。
(2)在小米 2S上如果想实现PTT语音消息的功能,播放语音时你可能这样做:


使用Audio进行扬声器播放的时候,当插入耳机时声音并未按预期的由耳机输出,而依旧使用的扬声器进行播放。如果您也是这样做的,那么我们建议您在这台机型上将MODE_IN_CALL与STREAM_MUSIC配对或者将Answerphone设置为false,从而让程序具有兼容性。
_
腾讯优测是专业的移动云测试平台,为应用、游戏、H5混合应用的研发团队提供产品质量检测与问题解决服务。不仅在线上平台提供自动化兼容性测试、云手机远程租用与调试、漏洞分析、自动化测试工具Xtest等多种质量检测工具,更为VIP客户配备了专家团队提供定制化综合测试解决方案。

相关文章:

  • Android IOS WebRTC 音视频开发总结(八十五)-- 使用WebRTC广播网络摄像头视频(下)...
  • jdbc conn.commit()提交事务和 rollback()使用
  • 每天一个linux命令:mkdir命令
  • 程序(进程)内存分布解析【转】
  • jenkins updatecenter更新插件有问题
  • Django+uwsgi+Nginx安装部署
  • 基于人脸识别的商业大数据4
  • 用xargs批量删除Redis的keys的技巧
  • php中的邮件技术
  • 一起参Ember.js讨论、问答社区。
  • 初学Redis(1)——认识Redis
  • 移动端流体布局
  • MongoDB sharding迁移那些事(三)
  • [转]Oracle 阳历转农历
  • V-rep学习笔记:转动关节1
  • [Vue CLI 3] 配置解析之 css.extract
  • Debian下无root权限使用Python访问Oracle
  • JavaScript工作原理(五):深入了解WebSockets,HTTP/2和SSE,以及如何选择
  • Laravel Telescope:优雅的应用调试工具
  • leetcode386. Lexicographical Numbers
  • mysql 5.6 原生Online DDL解析
  • Python - 闭包Closure
  • Spring框架之我见(三)——IOC、AOP
  • Vue 动态创建 component
  • webpack入门学习手记(二)
  • zookeeper系列(七)实战分布式命名服务
  • 笨办法学C 练习34:动态数组
  • 从伪并行的 Python 多线程说起
  • 大整数乘法-表格法
  • 关键词挖掘技术哪家强(一)基于node.js技术开发一个关键字查询工具
  • 那些被忽略的 JavaScript 数组方法细节
  • 批量截取pdf文件
  • 吐槽Javascript系列二:数组中的splice和slice方法
  • 异步
  • ​iOS实时查看App运行日志
  • ​人工智能之父图灵诞辰纪念日,一起来看最受读者欢迎的AI技术好书
  • #android不同版本废弃api,新api。
  • #mysql 8.0 踩坑日记
  • $.proxy和$.extend
  • (C语言)fread与fwrite详解
  • (草履虫都可以看懂的)PyQt子窗口向主窗口传递参数,主窗口接收子窗口信号、参数。
  • (附源码)spring boot车辆管理系统 毕业设计 031034
  • (附源码)spring boot球鞋文化交流论坛 毕业设计 141436
  • (十一)c52学习之旅-动态数码管
  • (一)RocketMQ初步认识
  • (一)基于IDEA的JAVA基础10
  • (转)负载均衡,回话保持,cookie
  • .md即markdown文件的基本常用编写语法
  • .net core 6 redis操作类
  • .net core IResultFilter 的 OnResultExecuted和OnResultExecuting的区别
  • .Net CoreRabbitMQ消息存储可靠机制
  • .Net Web窗口页属性
  • .net 生成二级域名
  • .NET中两种OCR方式对比
  • @CacheInvalidate(name = “xxx“, key = “#results.![a+b]“,multi = true)是什么意思