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

来源:互联网 发布:怎样开淘宝旗舰店 编辑:程序博客网 时间:2024/05/01 13:43

http://blog.csdn.net/l627859442/article/details/13628591

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

 1 2 3 4 5 6 7 8 9101112131415161718192021222324
   private static final int SW_HEADPHONE_INSERT = 0x02;   private static final int SW_MICROPHONE_INSERT = 0x04;   private static final int SW_LINEOUT_INSERT = 0x06;0x02&&0x04代表标准3.5mm耳机0x06&&0x04代表accessory使用ADB模拟耳机插入事件,如下:第一个参数代表动作类型(path switch),第二个参数代表“键”,第四个参数代表“值”(1:插入;0:拔出。)。Accessory 插入                            sendevent /dev/input/event5 5 4 1                            sendevent /dev/input/event5 5 6 1                            sendevent /dev/input/event5 0 0 0Accessory 拔出                            sendevent /dev/input/event5 5 4 0                            sendevent /dev/input/event5 5 6 0                            sendevent /dev/input/event5 0 0 0标准3.5耳机插入                            sendevent /dev/input/event5 5 4 1                            sendevent /dev/input/event5 5 2 1                            sendevent /dev/input/event5 0 0 0标准3.5耳机拔出                            sendevent /dev/input/event5 5 4 0                            sendevent /dev/input/event5 5 2 0                            sendevent /dev/input/event5 0 0 0

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

12345678
SystemService.javatry {                Slog.i(TAG, "Wired Accessory Observer");                // Listen for wired headset changes                new WiredAccessoryObserver(context);            } catch (Throwable e) {                reportWtf("starting WiredAccessoryObserver", e);            }

在WiredAccessoryObserver中,注册了开机广播,开机后,会开始所有相关的UEvent,并且开始监听。

 1 2 3 4 5 6 7 8 91011121314151617181920212223242526272829303132333435363738394041424344
WiredAccessoryObserver.java//所有要监听的UEventprivate 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;    }
 1 2 3 4 5 6 7 8 91011121314
//开始监听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事件。

 1 2 3 4 5 6 7 8 910111213
@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);        }    }

其中这些状态是从
root@android:/sys/class/switch # ls -l
ls -l
lrwxrwxrwx root root 2013-03-01 14:15 hdmi -> ../../devices/virtual/switch/hdmi
lrwxrwxrwx root root 2013-03-01 14:16 hdmi_audio -> ../../devices/virtual/switch/hdmi_audio
lrwxrwxrwx root root 2013-03-01 14:16 usb_audio -> ../../devices/virtual/switch/usb_audio
这些文件中读取的。
设备是定义在/devices/virtual/switch/下的。

最终会调用到AudioManager

1
mAudioManager.setWiredDeviceConnectionState(device, state, headsetName);

AudioManager的setWiredDeviceConnectionState实际是调用AudioService的setWiredDeviceConnectionState方法。

 1 2 3 4 5 6 7 8 91011
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);        }    }

最终会发送到上层一个广播:

 1 2 3 4 5 6 7 8 910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
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);    }

要想在状态栏添加耳机插入的图标,在SystemUI里面添加相关逻辑。耳机拔出通知也是一样的流程。

声明:eoe文章著作权属于作者,受法律保护,转载时请务必以超链接形式附带如下信息

原文作者: cnhua5

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


0 0
原创粉丝点击