Android4.1.2 耳机插入拔出通知流程分析

因为需要加一套新的耳机设备accessory并且展示耳机图标在状态栏,所以需要去看一下android上层的处理流程。
其实整个耳机插入的流程是:当硬件检测到耳机的插入,kernel上报UEvent到上层,上层接收到event后,调用硬件去切audio path, 硬件切换成功后,kernel发送UEvent给framework, 然后做show图标的动作。
想了解UEvent的流程,可以参看:

http://blog.csdn.net/piaozhiye/article/details/25098435

1、在系统启动过程中,在SystemService中会启动很多服务,包括一个WiredAccessoryObserver。

SystemService.java
try {
                Slog.i(TAG, "Wired Accessory Observer");
                // Listen for wired headset changes
                new WiredAccessoryObserver(context);
            } catch (Throwable e) {
                reportWtf("starting WiredAccessoryObserver", e);
            }
在WiredAccessoryObserver中,注册了开机广播,开机后,会开始所有相关的UEvent,并且开始监听。
WiredAccessoryObserver.java
//所有要监听的UEvent
private static List<UEventInfo> makeObservedUEventList() {
        List<UEventInfo> retVal = new ArrayList<UEventInfo>();
        UEventInfo uei;

        // Monitor h2w
        uei = new UEventInfo("h2w", BIT_HEADSET, BIT_HEADSET_NO_MIC);
        if (uei.checkSwitchExists()) {
            retVal.add(uei);
        } else {
            Slog.w(TAG, "This kernel does not have wired headset support");
        }

        // Monitor USB
        uei = new UEventInfo("usb_audio", BIT_USB_HEADSET_ANLG, BIT_USB_HEADSET_DGTL);
        if (uei.checkSwitchExists()) {
            retVal.add(uei);
        } else {
            Slog.w(TAG, "This kernel does not have usb audio support");
        }

        // Monitor HDMI
        //
        // If the kernel has support for the "hdmi_audio" switch, use that.  It will be signalled
        // only when the HDMI driver has a video mode configured, and the downstream sink indicates
        // support for audio in its EDID.
        //
        // If the kernel does not have an "hdmi_audio" switch, just fall back on the older "hdmi"
        // switch instead.
        uei = new UEventInfo("hdmi_audio", BIT_HDMI_AUDIO, 0);
        if (uei.checkSwitchExists()) {
            retVal.add(uei);
        } else {
            uei = new UEventInfo("hdmi", BIT_HDMI_AUDIO, 0);
            if (uei.checkSwitchExists()) {
                retVal.add(uei);
            } else {
                Slog.w(TAG, "This kernel does not have HDMI audio support");
            }
        }

        return retVal;
    }
开始监听
private final class BootCompletedReceiver extends BroadcastReceiver {
      @Override
      public void onReceive(Context context, Intent intent) {
        // At any given time accessories could be inserted
        // one on the board, one on the dock and one on HDMI:
        // observe three UEVENTs
        init();  // set initial status
        for (int i = 0; i < uEventInfo.size(); ++i) {
            UEventInfo uei = uEventInfo.get(i);
            startObserving("DEVPATH="+uei.getDevPath());
        }
      }
    }

在OnEvent中,实时监听UEvent事件。
@Override
    public void onUEvent(UEventObserver.UEvent event) {
        if (LOG) Slog.v(TAG, "Headset UEVENT: " + event.toString());

        try {
            String devPath = event.get("DEVPATH");
            String name = event.get("SWITCH_NAME");
            int state = Integer.parseInt(event.get("SWITCH_STATE"));
            updateState(devPath, name, state);
        } catch (NumberFormatException e) {
            Slog.e(TAG, "Could not parse switch state from event " + event);
        }
    }

其中这些状态是从
shell@hammerhead:/ $ ls sys/class/switch/ -l                                   
lrwxrwxrwx root     root              2014-05-06 09:44 h2w -> ../../devices/virtual/switch/h2w
lrwxrwxrwx root     root              2014-05-06 09:44 hdmi -> ../../devices/virtual/switch/hdmi
lrwxrwxrwx root     root              2014-05-06 09:44 hdmi_audio -> ../../devices/virtual/switch/hdmi_audio
lrwxrwxrwx root     root              2014-05-06 09:44 usb_audio -> ../../devices/virtual/switch/usb_audio
lrwxrwxrwx root     root              2014-05-06 09:44 wfd -> ../../devices/virtual/switch/wfd
这些文件中读取的。
设备是定义在/devices/virtual/switch/下的。

最终会调用到AudioManager

mAudioManager.setWiredDeviceConnectionState(device, state, headsetName);

AudioManager的setWiredDeviceConnectionState实际是调用AudioService的setWiredDeviceConnectionState方法。
public void setWiredDeviceConnectionState(int device, int state, String name) {
        synchronized (mConnectedDevices) {
            int delay = checkSendBecomingNoisyIntent(device, state);
            queueMsgUnderWakeLock(mAudioHandler,
                    MSG_SET_WIRED_DEVICE_CONNECTION_STATE,
                    device,
                    state,
                    name,
                    delay);
        }
    }

最终会发送到上层一个广播:
private void sendDeviceConnectionIntent(int device, int state, String name)
    {
        Intent intent = new Intent();

        intent.putExtra("state", state);
        intent.putExtra("name", name);
        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
        int connType = 0;
        if (device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) {
            connType = AudioRoutesInfo.MAIN_HEADSET;
            intent.setAction(Intent.ACTION_HEADSET_PLUG);
            intent.putExtra("microphone", 1);
        } else if (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) {
            connType = AudioRoutesInfo.MAIN_HEADPHONES;
            intent.setAction(Intent.ACTION_HEADSET_PLUG);
            intent.putExtra("microphone", 0);
        } else if (device == AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET) {
            connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS;
            intent.setAction(Intent.ACTION_ANALOG_AUDIO_DOCK_PLUG);
        } else if (device == AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET) {
            connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS;
            intent.setAction(Intent.ACTION_DIGITAL_AUDIO_DOCK_PLUG);
        } else if (device == AudioSystem.DEVICE_OUT_AUX_DIGITAL) {
            connType = AudioRoutesInfo.MAIN_HDMI;
            intent.setAction(Intent.ACTION_HDMI_AUDIO_PLUG);
        } else if (device == AudioSystem.DEVICE_OUT_ANC_HEADSET) {
            connType = AudioRoutesInfo.MAIN_HEADSET;
            intent.setAction(Intent.ACTION_HEADSET_PLUG);
            intent.putExtra("microphone", 1);
        } else if (device == AudioSystem.DEVICE_OUT_ANC_HEADPHONE) {
            connType = AudioRoutesInfo.MAIN_HEADPHONES;
            intent.setAction(Intent.ACTION_HEADSET_PLUG);
            intent.putExtra("microphone", 0);
        }

        synchronized (mCurAudioRoutes) {
            if (connType != 0) {
                int newConn = mCurAudioRoutes.mMainType;
                if (state != 0) {
                    newConn |= connType;
                } else {
                    newConn &= ~connType;
                }
                if (newConn != mCurAudioRoutes.mMainType) {
                    mCurAudioRoutes.mMainType = newConn;
                    sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
                            SENDMSG_NOOP, 0, 0, null, 0);
                }
            }
        }
        ActivityManagerNative.broadcastStickyIntent(intent, null);
    }

原文作者: cnhua5

原文地址: http://my.eoe.cn/535201/archive/1252.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值