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
- Android4.1.2 耳机插入拔出通知流程分析
- Android4.1.2 耳机插入拔出通知流程分析
- Android4.1.2 耳机插入拔出通知流程分析
- android耳机插入\拔出事件上报流程
- [学习记录]Android4.0耳机插入广播发送流程分析
- [学习记录]Android4.0耳机插入广播发送流程分析
- Android4.0耳机插入广播发送流程分析
- 检测耳机插入拔出
- iphone检测耳机插入/拔出
- iphone检测耳机插入/拔出
- iphone检测耳机插入/拔出
- iphone检测耳机插入/拔出
- iphone检测耳机插入/拔出
- iphone检测耳机插入/拔出
- iphone检测耳机插入/拔出
- iphone检测耳机插入/拔出
- iphone检测耳机插入/拔出
- 耳机 插入/拔出 代码监测
- windows activex 打包需要注意的地方
- linux WEB服务器安装地址
- MyBatis快速转换工具
- 二叉树遍历 层序遍历
- Cocos2d-x利用CCSpriteBatchNode提高渲染效率
- Android4.1.2 耳机插入拔出通知流程分析
- EXT4.1表单提交(非AJAX)
- Android中的系统广播集合
- <s:hidden name="XX" label="YY" value%{属性}/>
- 骑马修栅栏
- 推荐系统算法分类
- iOS - 正则表达式判断邮箱、身份证..是否正确
- ubuntu开启启动过程&&开启自动启动 &&chkconfig
- java中保留两位小数