Android 耳机事件传递流程

本文详细分析了Android系统中耳机拔插事件的传递流程,从驱动层的事件上传到framework层的代码分析,涉及InputManagerService、WiredAccessoryManager等关键组件,最后在AudioService中处理耳机状态。
摘要由CSDN通过智能技术生成

在项目中,遇到问题:插入不带麦耳机,状态栏显示仍然是带麦图标
解决此问题涉及到耳机的拔插事件传递流程,在此分析一下Android系统,耳机拔插流程源码分析。

Android系统的耳机目前可以实现拍照、暂停/播放、打电话等功能,这一切的基础是耳机拔插成功,结合InputManagerService的相关知识,主要从framework层面分析耳机插拔事件的传递。

一、驱动层的事件上传

使用adb 命令可以查看当前手机插入的耳机状态,命令为:adb shell cat /sys/class/switch/h2w/state

  • 插入带麦耳机

ubuntu@ubuntu:~/headset$ adb shell cat /sys/class/switch/h2w/state
11

  • 插入不带麦耳机

ubuntu@ubuntu:~/headset$ adb shell cat /sys/class/switch/h2w/state
9

通过这个命令,我们可以初步判断,状态栏耳机显示异常问题是出现在驱动层还是上层。

二、framework层代码分析

前文提到,耳机拔插主要涉及到InputManagerService这个系统重量级服务。关于IMS(inoutManagerService)的具体介绍,请参考此文章:http://blog.csdn.net/jinzhuojun/article/details/41909159 ,作者很详尽的介绍了IPM的事件读取和分发过程。 本文章只挑拣IPM中与耳机事件相关的内容分析。
Android系统的事件主要分为两类:

  • 按键事件(KeyEvent)
    由物理按键产生的事件。 对于嵌入式设备,通常不会保留太多的物理按键,手机一般有Home, Back, Menu, Volume Down, Volume Up,我们讨论的耳机事件也归类在此。

  • 触摸事件(TouchEvent)
    在手机屏幕上面的点击、拖动事件,以及它们的组合产生的各种事件。

2.1 涉及到的类

InputManagerService.java
/framework/base/services/core/java/com/android/server/input/InputManagerService.java

WiredAccessoryManager.java
/framework/base/services/core/java/com/android/server/WiredAccessoryManager.java

config.xml
/framework/base/core/res/res/values/config.xml

SystemServer.java
/framework/base/services/java/com/android/server/SystemServer.java

AudioManager.java
/framework/base/media/java/android/media/AudioManager.java

AudioService.java
framework/base/media/java/android/media/AudioService.java

2.2 设置Event上传方式
Android中有两种Event上传方式:InputEvent(linux的 /dev/input/event subsystem),和UEvent(framework下的比较老的event方式),两种方式的切换是通过属性配置实现的,在config.xml文件中,有如下代码:

<!-- When true use the linux /dev/input/event subsystem to detect the switch changes on the headphone/microphone jack. 
When false use the older uevent framework. -->
<bool name="config_useDevInputEventForAudioJack">false</bool>
    public InputManagerService(Context context) {
        this.mContext = context;
        this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());

        mUseDevInputEventForAudioJack =
                context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
        Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="
                + mUseDevInputEventForAudioJack);
        mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());

        String doubleTouchGestureEnablePath = context.getResources().getString(
                R.string.config_doubleTouchGestureEnableFile);
        mDoubleTouchGestureEnableFile = TextUtils.isEmpty(doubleTouchGestureEnablePath) ? null :
            new File(doubleTouchGestureEnablePath);

        LocalServices.addService(InputManagerInternal.class, new LocalService());
    }

useDevInputEventForAudioJack设置为true使用/dev/input/event,FALSE时设置为UEvent.
在这里我们可以看到,当前使用的是UEvent方式。(UEvent方式支持热插拔,是一种适合耳机拔插事件的方式。)

2.2 IMS 耳机事件传递
插入耳机后,驱动层会将耳机事件首先,传递到IMS的notifySwitch()函数,驱动层的检测与向上传递在此分析。

@2.2.1 notifySwitch()

    // Native callback.
    private void notifySwitch(long whenNanos, int switchValues, int switchMask) {
        if (DEBUG) {
            Slog.d(TAG, "notifySwitch: values=" + Integer.toHexString(switchValues)
                    + ", mask=" + Integer.toHexString(switchMask));
        }
.....
.....

//此处是最重要的内容,在这里,会将耳机拔插时间传递给mWiredAccessoryCallbacks回调
        if (mUseDevInputEventForAudioJack && (switchMask & SW_JACK_BITS) != 0) {
            mWiredAccessoryCallbacks.notifyWiredAccessoryChanged(whenNanos, switchValues,
                    switchMask);
        }
......
...
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值