diff options
Diffstat (limited to 'services/java/com/android/server/WiredAccessoryObserver.java')
-rw-r--r-- | services/java/com/android/server/WiredAccessoryObserver.java | 305 |
1 files changed, 153 insertions, 152 deletions
diff --git a/services/java/com/android/server/WiredAccessoryObserver.java b/services/java/com/android/server/WiredAccessoryObserver.java index 96ac493..56c0fdf 100644 --- a/services/java/com/android/server/WiredAccessoryObserver.java +++ b/services/java/com/android/server/WiredAccessoryObserver.java @@ -16,12 +16,12 @@ package com.android.server; -import android.app.ActivityManagerNative; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Handler; +import android.os.Looper; import android.os.Message; import android.os.PowerManager; import android.os.PowerManager.WakeLock; @@ -39,7 +39,7 @@ import java.util.List; /** * <p>WiredAccessoryObserver monitors for a wired headset on the main board or dock. */ -class WiredAccessoryObserver extends UEventObserver { +final class WiredAccessoryObserver extends UEventObserver { private static final String TAG = WiredAccessoryObserver.class.getSimpleName(); private static final boolean LOG = true; private static final int BIT_HEADSET = (1 << 0); @@ -50,122 +50,32 @@ class WiredAccessoryObserver extends UEventObserver { private static final int SUPPORTED_HEADSETS = (BIT_HEADSET|BIT_HEADSET_NO_MIC| BIT_USB_HEADSET_ANLG|BIT_USB_HEADSET_DGTL| BIT_HDMI_AUDIO); - private static final int HEADSETS_WITH_MIC = BIT_HEADSET; - private static class UEventInfo { - private final String mDevName; - private final int mState1Bits; - private final int mState2Bits; - - public UEventInfo(String devName, int state1Bits, int state2Bits) { - mDevName = devName; - mState1Bits = state1Bits; - mState2Bits = state2Bits; - } - - public String getDevName() { return mDevName; } - - public String getDevPath() { - return String.format("/devices/virtual/switch/%s", mDevName); - } - - public String getSwitchStatePath() { - return String.format("/sys/class/switch/%s/state", mDevName); - } - - public boolean checkSwitchExists() { - File f = new File(getSwitchStatePath()); - return ((null != f) && f.exists()); - } - - public int computeNewHeadsetState(int headsetState, int switchState) { - int preserveMask = ~(mState1Bits | mState2Bits); - int setBits = ((switchState == 1) ? mState1Bits : - ((switchState == 2) ? mState2Bits : 0)); - - return ((headsetState & preserveMask) | setBits); - } - } - - 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"); - } + private final Object mLock = new Object(); - // 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 static List<UEventInfo> uEventInfo = makeObservedUEventList(); + private final Context mContext; + private final WakeLock mWakeLock; // held while there is a pending route change + private final AudioManager mAudioManager; + private final List<UEventInfo> mUEventInfo; private int mHeadsetState; private int mPrevHeadsetState; private String mHeadsetName; - private final Context mContext; - private final WakeLock mWakeLock; // held while there is a pending route change - - private final AudioManager mAudioManager; - public WiredAccessoryObserver(Context context) { mContext = context; + PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WiredAccessoryObserver"); mWakeLock.setReferenceCounted(false); mAudioManager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE); + mUEventInfo = makeObservedUEventList(); + context.registerReceiver(new BootCompletedReceiver(), new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null); } - 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()); - } - } - } - @Override public void onUEvent(UEventObserver.UEvent event) { if (LOG) Slog.v(TAG, "Headset UEVENT: " + event.toString()); @@ -174,56 +84,64 @@ class WiredAccessoryObserver extends UEventObserver { String devPath = event.get("DEVPATH"); String name = event.get("SWITCH_NAME"); int state = Integer.parseInt(event.get("SWITCH_STATE")); - updateState(devPath, name, state); + synchronized (mLock) { + updateStateLocked(devPath, name, state); + } } catch (NumberFormatException e) { Slog.e(TAG, "Could not parse switch state from event " + event); } } - private synchronized final void updateState(String devPath, String name, int state) - { - for (int i = 0; i < uEventInfo.size(); ++i) { - UEventInfo uei = uEventInfo.get(i); - if (devPath.equals(uei.getDevPath())) { - update(name, uei.computeNewHeadsetState(mHeadsetState, state)); - return; + private void bootCompleted() { + synchronized (mLock) { + char[] buffer = new char[1024]; + mPrevHeadsetState = mHeadsetState; + + if (LOG) Slog.v(TAG, "init()"); + + for (int i = 0; i < mUEventInfo.size(); ++i) { + UEventInfo uei = mUEventInfo.get(i); + try { + int curState; + FileReader file = new FileReader(uei.getSwitchStatePath()); + int len = file.read(buffer, 0, 1024); + file.close(); + curState = Integer.valueOf((new String(buffer, 0, len)).trim()); + + if (curState > 0) { + updateStateLocked(uei.getDevPath(), uei.getDevName(), curState); + } + } catch (FileNotFoundException e) { + Slog.w(TAG, uei.getSwitchStatePath() + + " not found while attempting to determine initial switch state"); + } catch (Exception e) { + Slog.e(TAG, "" , e); + } } } - } - - private synchronized final void init() { - char[] buffer = new char[1024]; - mPrevHeadsetState = mHeadsetState; - - if (LOG) Slog.v(TAG, "init()"); - for (int i = 0; i < uEventInfo.size(); ++i) { - UEventInfo uei = uEventInfo.get(i); - try { - int curState; - FileReader file = new FileReader(uei.getSwitchStatePath()); - int len = file.read(buffer, 0, 1024); - file.close(); - curState = Integer.valueOf((new String(buffer, 0, len)).trim()); - - if (curState > 0) { - updateState(uei.getDevPath(), uei.getDevName(), curState); - } + // At any given time accessories could be inserted + // one on the board, one on the dock and one on HDMI: + // observe three UEVENTs + for (int i = 0; i < mUEventInfo.size(); ++i) { + UEventInfo uei = mUEventInfo.get(i); + startObserving("DEVPATH="+uei.getDevPath()); + } + } - } catch (FileNotFoundException e) { - Slog.w(TAG, uei.getSwitchStatePath() + - " not found while attempting to determine initial switch state"); - } catch (Exception e) { - Slog.e(TAG, "" , e); + private void updateStateLocked(String devPath, String name, int state) { + for (int i = 0; i < mUEventInfo.size(); ++i) { + UEventInfo uei = mUEventInfo.get(i); + if (devPath.equals(uei.getDevPath())) { + updateLocked(name, uei.computeNewHeadsetState(mHeadsetState, state)); + return; } } } - private synchronized final void update(String newName, int newState) { + private void updateLocked(String newName, int newState) { // Retain only relevant bits int headsetState = newState & SUPPORTED_HEADSETS; - int newOrOld = headsetState | mHeadsetState; - int delay = 0; int usb_headset_anlg = headsetState & BIT_USB_HEADSET_ANLG; int usb_headset_dgtl = headsetState & BIT_USB_HEADSET_DGTL; int h2w_headset = headsetState & (BIT_HEADSET | BIT_HEADSET_NO_MIC); @@ -254,28 +172,26 @@ class WiredAccessoryObserver extends UEventObserver { mHeadsetState = headsetState; mWakeLock.acquire(); - mHandler.sendMessage(mHandler.obtainMessage(0, - mHeadsetState, - mPrevHeadsetState, - mHeadsetName)); + + Message msg = mHandler.obtainMessage(0, mHeadsetState, mPrevHeadsetState, mHeadsetName); + mHandler.sendMessage(msg); } - private synchronized final void setDevicesState(int headsetState, - int prevHeadsetState, - String headsetName) { - int allHeadsets = SUPPORTED_HEADSETS; - for (int curHeadset = 1; allHeadsets != 0; curHeadset <<= 1) { - if ((curHeadset & allHeadsets) != 0) { - setDeviceState(curHeadset, headsetState, prevHeadsetState, headsetName); - allHeadsets &= ~curHeadset; + private void setDevicesState( + int headsetState, int prevHeadsetState, String headsetName) { + synchronized (mLock) { + int allHeadsets = SUPPORTED_HEADSETS; + for (int curHeadset = 1; allHeadsets != 0; curHeadset <<= 1) { + if ((curHeadset & allHeadsets) != 0) { + setDeviceStateLocked(curHeadset, headsetState, prevHeadsetState, headsetName); + allHeadsets &= ~curHeadset; + } } } } - private final void setDeviceState(int headset, - int headsetState, - int prevHeadsetState, - String headsetName) { + private void setDeviceStateLocked(int headset, + int headsetState, int prevHeadsetState, String headsetName) { if ((headsetState & headset) != (prevHeadsetState & headset)) { int device; int state; @@ -308,11 +224,96 @@ class WiredAccessoryObserver extends UEventObserver { } } - private final Handler mHandler = new Handler() { + 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 Handler mHandler = new Handler(Looper.myLooper(), null, true) { @Override public void handleMessage(Message msg) { setDevicesState(msg.arg1, msg.arg2, (String)msg.obj); mWakeLock.release(); } }; + + private static final class UEventInfo { + private final String mDevName; + private final int mState1Bits; + private final int mState2Bits; + + public UEventInfo(String devName, int state1Bits, int state2Bits) { + mDevName = devName; + mState1Bits = state1Bits; + mState2Bits = state2Bits; + } + + public String getDevName() { return mDevName; } + + public String getDevPath() { + return String.format("/devices/virtual/switch/%s", mDevName); + } + + public String getSwitchStatePath() { + return String.format("/sys/class/switch/%s/state", mDevName); + } + + public boolean checkSwitchExists() { + File f = new File(getSwitchStatePath()); + return ((null != f) && f.exists()); + } + + public int computeNewHeadsetState(int headsetState, int switchState) { + int preserveMask = ~(mState1Bits | mState2Bits); + int setBits = ((switchState == 1) ? mState1Bits : + ((switchState == 2) ? mState2Bits : 0)); + + return ((headsetState & preserveMask) | setBits); + } + } + + private final class BootCompletedReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + bootCompleted(); + } + } } |