Loading core/res/res/values/config.xml +4 −0 Original line number Original line Diff line number Diff line Loading @@ -960,4 +960,8 @@ --> --> <bool name="config_enableWifiDisplay">false</bool> <bool name="config_enableWifiDisplay">false</bool> <!-- 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> </resources> </resources> core/res/res/values/symbols.xml +2 −1 Original line number Original line Diff line number Diff line Loading @@ -271,6 +271,7 @@ <java-symbol type="bool" name="config_enableScreenshotChord" /> <java-symbol type="bool" name="config_enableScreenshotChord" /> <java-symbol type="bool" name="config_bluetooth_default_profiles" /> <java-symbol type="bool" name="config_bluetooth_default_profiles" /> <java-symbol type="bool" name="config_enableWifiDisplay" /> <java-symbol type="bool" name="config_enableWifiDisplay" /> <java-symbol type="bool" name="config_useDevInputEventForAudioJack" /> <java-symbol type="integer" name="config_cursorWindowSize" /> <java-symbol type="integer" name="config_cursorWindowSize" /> <java-symbol type="integer" name="config_longPressOnPowerBehavior" /> <java-symbol type="integer" name="config_longPressOnPowerBehavior" /> Loading services/java/com/android/server/SystemServer.java +4 −3 Original line number Original line Diff line number Diff line Loading @@ -631,11 +631,12 @@ class ServerThread extends Thread { } } try { try { Slog.i(TAG, "Wired Accessory Observer"); Slog.i(TAG, "Wired Accessory Manager"); // Listen for wired headset changes // Listen for wired headset changes new WiredAccessoryObserver(context); inputManager.setWiredAccessoryCallbacks( new WiredAccessoryManager(context, inputManager)); } catch (Throwable e) { } catch (Throwable e) { reportWtf("starting WiredAccessoryObserver", e); reportWtf("starting WiredAccessoryManager", e); } } try { try { Loading services/java/com/android/server/WiredAccessoryObserver.java→services/java/com/android/server/WiredAccessoryManager.java +432 −0 Original line number Original line Diff line number Diff line Loading @@ -29,6 +29,15 @@ import android.os.UEventObserver; import android.util.Slog; import android.util.Slog; import android.media.AudioManager; import android.media.AudioManager; import android.util.Log; import android.util.Log; import android.view.InputDevice; import com.android.internal.R; import com.android.server.input.InputManagerService; import com.android.server.input.InputManagerService.WiredAccessoryCallbacks; import static com.android.server.input.InputManagerService.SW_HEADPHONE_INSERT; import static com.android.server.input.InputManagerService.SW_MICROPHONE_INSERT; import static com.android.server.input.InputManagerService.SW_HEADPHONE_INSERT_BIT; import static com.android.server.input.InputManagerService.SW_MICROPHONE_INSERT_BIT; import java.io.File; import java.io.File; import java.io.FileReader; import java.io.FileReader; Loading @@ -37,11 +46,14 @@ import java.util.ArrayList; import java.util.List; import java.util.List; /** /** * <p>WiredAccessoryObserver monitors for a wired headset on the main board or dock. * <p>WiredAccessoryManager monitors for a wired headset on the main board or dock using * both the InputManagerService notifyWiredAccessoryChanged interface and the UEventObserver * subsystem. */ */ final class WiredAccessoryObserver extends UEventObserver { final class WiredAccessoryManager implements WiredAccessoryCallbacks { private static final String TAG = WiredAccessoryObserver.class.getSimpleName(); private static final String TAG = WiredAccessoryManager.class.getSimpleName(); private static final boolean LOG = true; private static final boolean LOG = true; private static final int BIT_HEADSET = (1 << 0); private static final int BIT_HEADSET = (1 << 0); private static final int BIT_HEADSET_NO_MIC = (1 << 1); private static final int BIT_HEADSET_NO_MIC = (1 << 1); private static final int BIT_USB_HEADSET_ANLG = (1 << 2); private static final int BIT_USB_HEADSET_ANLG = (1 << 2); Loading @@ -51,94 +63,108 @@ final class WiredAccessoryObserver extends UEventObserver { BIT_USB_HEADSET_ANLG|BIT_USB_HEADSET_DGTL| BIT_USB_HEADSET_ANLG|BIT_USB_HEADSET_DGTL| BIT_HDMI_AUDIO); BIT_HDMI_AUDIO); private static final String NAME_H2W = "h2w"; private static final String NAME_USB_AUDIO = "usb_audio"; private static final String NAME_HDMI_AUDIO = "hdmi_audio"; private static final String NAME_HDMI = "hdmi"; private static final int MSG_NEW_DEVICE_STATE = 1; private final Object mLock = new Object(); private final Object mLock = new Object(); private final Context mContext; private final WakeLock mWakeLock; // held while there is a pending route change private final WakeLock mWakeLock; // held while there is a pending route change private final AudioManager mAudioManager; private final AudioManager mAudioManager; private final List<UEventInfo> mUEventInfo; private int mHeadsetState; private int mHeadsetState; private int mPrevHeadsetState; private String mHeadsetName; public WiredAccessoryObserver(Context context) { private int mSwitchValues; mContext = context; private final WiredAccessoryObserver mObserver; private final InputManagerService mInputManager; private final boolean mUseDevInputEventForAudioJack; public WiredAccessoryManager(Context context, InputManagerService inputManager) { PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WiredAccessoryObserver"); mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WiredAccessoryManager"); mWakeLock.setReferenceCounted(false); mWakeLock.setReferenceCounted(false); mAudioManager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE); mAudioManager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE); mInputManager = inputManager; mUEventInfo = makeObservedUEventList(); mUseDevInputEventForAudioJack = context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack); context.registerReceiver(new BootCompletedReceiver(), mObserver = new WiredAccessoryObserver(); new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null); } context.registerReceiver(new BroadcastReceiver() { @Override @Override public void onUEvent(UEventObserver.UEvent event) { public void onReceive(Context ctx, Intent intent) { if (LOG) Slog.v(TAG, "Headset UEVENT: " + event.toString()); bootCompleted(); } }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null); } try { private void bootCompleted() { String devPath = event.get("DEVPATH"); if (mUseDevInputEventForAudioJack) { String name = event.get("SWITCH_NAME"); int switchValues = 0; int state = Integer.parseInt(event.get("SWITCH_STATE")); if (mInputManager.getSwitchState(-1, InputDevice.SOURCE_ANY, SW_HEADPHONE_INSERT) == 1) { synchronized (mLock) { switchValues |= SW_HEADPHONE_INSERT_BIT; updateStateLocked(devPath, name, state); } } } catch (NumberFormatException e) { if (mInputManager.getSwitchState(-1, InputDevice.SOURCE_ANY, SW_MICROPHONE_INSERT) == 1) { Slog.e(TAG, "Could not parse switch state from event " + event); switchValues |= SW_MICROPHONE_INSERT_BIT; } } notifyWiredAccessoryChanged(0, switchValues, SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT); } } private void bootCompleted() { mObserver.init(); } @Override public void notifyWiredAccessoryChanged(long whenNanos, int switchValues, int switchMask) { if (LOG) Slog.v(TAG, "notifyWiredAccessoryChanged: when=" + whenNanos + " bits=" + switchCodeToString(switchValues, switchMask) + " mask=" + Integer.toHexString(switchMask)); synchronized (mLock) { synchronized (mLock) { char[] buffer = new char[1024]; int headset; mPrevHeadsetState = mHeadsetState; mSwitchValues = (mSwitchValues & ~switchMask) | switchValues; switch (mSwitchValues & (SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT)) { case 0: headset = 0; break; if (LOG) Slog.v(TAG, "init()"); case SW_HEADPHONE_INSERT_BIT: headset = BIT_HEADSET_NO_MIC; break; for (int i = 0; i < mUEventInfo.size(); ++i) { case SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT: UEventInfo uei = mUEventInfo.get(i); headset = BIT_HEADSET; try { break; 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) { case SW_MICROPHONE_INSERT_BIT: updateStateLocked(uei.getDevPath(), uei.getDevName(), curState); headset = BIT_HEADSET; } break; } catch (FileNotFoundException e) { Slog.w(TAG, uei.getSwitchStatePath() + " not found while attempting to determine initial switch state"); } catch (Exception e) { Slog.e(TAG, "" , e); } } } // At any given time accessories could be inserted default: // one on the board, one on the dock and one on HDMI: headset = 0; // observe three UEVENTs break; for (int i = 0; i < mUEventInfo.size(); ++i) { UEventInfo uei = mUEventInfo.get(i); startObserving("DEVPATH="+uei.getDevPath()); } } } private void updateStateLocked(String devPath, String name, int state) { updateLocked(NAME_H2W, headset); 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; } } } } } /** * Compare the existing headset state with the new state and pass along accordingly. Note * that this only supports a single headset at a time. Inserting both a usb and jacked headset * results in support for the last one plugged in. Similarly, unplugging either is seen as * unplugging all. * * @param newName One of the NAME_xxx variables defined above. * @param newState 0 or one of the BIT_xxx variables defined above. */ private void updateLocked(String newName, int newState) { private void updateLocked(String newName, int newState) { // Retain only relevant bits // Retain only relevant bits int headsetState = newState & SUPPORTED_HEADSETS; int headsetState = newState & SUPPORTED_HEADSETS; Loading @@ -147,19 +173,27 @@ final class WiredAccessoryObserver extends UEventObserver { int h2w_headset = headsetState & (BIT_HEADSET | BIT_HEADSET_NO_MIC); int h2w_headset = headsetState & (BIT_HEADSET | BIT_HEADSET_NO_MIC); boolean h2wStateChange = true; boolean h2wStateChange = true; boolean usbStateChange = true; boolean usbStateChange = true; if (LOG) Slog.v(TAG, "newName=" + newName + " newState=" + newState + " headsetState=" + headsetState + " prev headsetState=" + mHeadsetState); if (mHeadsetState == headsetState) { Log.e(TAG, "No state change."); return; } // reject all suspect transitions: only accept state changes from: // reject all suspect transitions: only accept state changes from: // - a: 0 heaset to 1 headset // - a: 0 headset to 1 headset // - b: 1 headset to 0 headset // - b: 1 headset to 0 headset if (LOG) Slog.v(TAG, "newState = "+newState+", headsetState = "+headsetState+"," if (h2w_headset == (BIT_HEADSET | BIT_HEADSET_NO_MIC)) { + "mHeadsetState = "+mHeadsetState); Log.e(TAG, "Invalid combination, unsetting h2w flag"); if (mHeadsetState == headsetState || ((h2w_headset & (h2w_headset - 1)) != 0)) { Log.e(TAG, "unsetting h2w flag"); h2wStateChange = false; h2wStateChange = false; } } // - c: 0 usb headset to 1 usb headset // - c: 0 usb headset to 1 usb headset // - d: 1 usb headset to 0 usb headset // - d: 1 usb headset to 0 usb headset if ((usb_headset_anlg >> 2) == 1 && (usb_headset_dgtl >> 3) == 1) { if (usb_headset_anlg == BIT_USB_HEADSET_ANLG && usb_headset_dgtl == BIT_USB_HEADSET_DGTL) { Log.e(TAG, "unsetting usb flag"); Log.e(TAG, "Invalid combination, unsetting usb flag"); usbStateChange = false; usbStateChange = false; } } if (!h2wStateChange && !usbStateChange) { if (!h2wStateChange && !usbStateChange) { Loading @@ -167,16 +201,26 @@ final class WiredAccessoryObserver extends UEventObserver { return; return; } } mHeadsetName = newName; mPrevHeadsetState = mHeadsetState; mHeadsetState = headsetState; mWakeLock.acquire(); mWakeLock.acquire(); Message msg = mHandler.obtainMessage(0, mHeadsetState, mPrevHeadsetState, mHeadsetName); Message msg = mHandler.obtainMessage(MSG_NEW_DEVICE_STATE, headsetState, mHeadsetState, newName); mHandler.sendMessage(msg); mHandler.sendMessage(msg); mHeadsetState = headsetState; } } private final Handler mHandler = new Handler(Looper.myLooper(), null, true) { @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_NEW_DEVICE_STATE: setDevicesState(msg.arg1, msg.arg2, (String)msg.obj); mWakeLock.release(); } } }; private void setDevicesState( private void setDevicesState( int headsetState, int prevHeadsetState, String headsetName) { int headsetState, int prevHeadsetState, String headsetName) { synchronized (mLock) { synchronized (mLock) { Loading Loading @@ -224,20 +268,77 @@ final class WiredAccessoryObserver extends UEventObserver { } } } } private static List<UEventInfo> makeObservedUEventList() { private String switchCodeToString(int switchValues, int switchMask) { StringBuffer sb = new StringBuffer(); if ((switchMask & SW_HEADPHONE_INSERT_BIT) != 0 && (switchValues & SW_HEADPHONE_INSERT_BIT) != 0) { sb.append("SW_HEADPHONE_INSERT "); } if ((switchMask & SW_MICROPHONE_INSERT_BIT) != 0 && (switchValues & SW_MICROPHONE_INSERT_BIT) != 0) { sb.append("SW_MICROPHONE_INSERT"); } return sb.toString(); } class WiredAccessoryObserver extends UEventObserver { private final List<UEventInfo> mUEventInfo; public WiredAccessoryObserver() { mUEventInfo = makeObservedUEventList(); } void init() { synchronized (mLock) { if (LOG) Slog.v(TAG, "init()"); char[] buffer = new char[1024]; 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); } } } // 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()); } } private List<UEventInfo> makeObservedUEventList() { List<UEventInfo> retVal = new ArrayList<UEventInfo>(); List<UEventInfo> retVal = new ArrayList<UEventInfo>(); UEventInfo uei; UEventInfo uei; // Monitor h2w // Monitor h2w uei = new UEventInfo("h2w", BIT_HEADSET, BIT_HEADSET_NO_MIC); if (!mUseDevInputEventForAudioJack) { uei = new UEventInfo(NAME_H2W, BIT_HEADSET, BIT_HEADSET_NO_MIC); if (uei.checkSwitchExists()) { if (uei.checkSwitchExists()) { retVal.add(uei); retVal.add(uei); } else { } else { Slog.w(TAG, "This kernel does not have wired headset support"); Slog.w(TAG, "This kernel does not have wired headset support"); } } } // Monitor USB // Monitor USB uei = new UEventInfo("usb_audio", BIT_USB_HEADSET_ANLG, BIT_USB_HEADSET_DGTL); uei = new UEventInfo(NAME_USB_AUDIO, BIT_USB_HEADSET_ANLG, BIT_USB_HEADSET_DGTL); if (uei.checkSwitchExists()) { if (uei.checkSwitchExists()) { retVal.add(uei); retVal.add(uei); } else { } else { Loading @@ -246,17 +347,17 @@ final class WiredAccessoryObserver extends UEventObserver { // Monitor HDMI // Monitor HDMI // // // If the kernel has support for the "hdmi_audio" switch, use that. It will be signalled // If the kernel has support for the "hdmi_audio" switch, use that. It will be // only when the HDMI driver has a video mode configured, and the downstream sink indicates // signalled only when the HDMI driver has a video mode configured, and the downstream // support for audio in its EDID. // 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" // If the kernel does not have an "hdmi_audio" switch, just fall back on the older // switch instead. // "hdmi" switch instead. uei = new UEventInfo("hdmi_audio", BIT_HDMI_AUDIO, 0); uei = new UEventInfo(NAME_HDMI_AUDIO, BIT_HDMI_AUDIO, 0); if (uei.checkSwitchExists()) { if (uei.checkSwitchExists()) { retVal.add(uei); retVal.add(uei); } else { } else { uei = new UEventInfo("hdmi", BIT_HDMI_AUDIO, 0); uei = new UEventInfo(NAME_HDMI, BIT_HDMI_AUDIO, 0); if (uei.checkSwitchExists()) { if (uei.checkSwitchExists()) { retVal.add(uei); retVal.add(uei); } else { } else { Loading @@ -267,15 +368,33 @@ final class WiredAccessoryObserver extends UEventObserver { return retVal; return retVal; } } private final Handler mHandler = new Handler(Looper.myLooper(), null, true) { @Override @Override public void handleMessage(Message msg) { public void onUEvent(UEventObserver.UEvent event) { setDevicesState(msg.arg1, msg.arg2, (String)msg.obj); if (LOG) Slog.v(TAG, "Headset UEVENT: " + event.toString()); mWakeLock.release(); try { String devPath = event.get("DEVPATH"); String name = event.get("SWITCH_NAME"); int state = Integer.parseInt(event.get("SWITCH_STATE")); synchronized (mLock) { updateStateLocked(devPath, name, state); } } catch (NumberFormatException e) { Slog.e(TAG, "Could not parse switch state from event " + event); } } 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 static final class UEventInfo { private final class UEventInfo { private final String mDevName; private final String mDevName; private final int mState1Bits; private final int mState1Bits; private final int mState2Bits; private final int mState2Bits; Loading @@ -298,7 +417,7 @@ final class WiredAccessoryObserver extends UEventObserver { public boolean checkSwitchExists() { public boolean checkSwitchExists() { File f = new File(getSwitchStatePath()); File f = new File(getSwitchStatePath()); return ((null != f) && f.exists()); return f.exists(); } } public int computeNewHeadsetState(int headsetState, int switchState) { public int computeNewHeadsetState(int headsetState, int switchState) { Loading @@ -309,11 +428,5 @@ final class WiredAccessoryObserver extends UEventObserver { return ((headsetState & preserveMask) | setBits); return ((headsetState & preserveMask) | setBits); } } } } private final class BootCompletedReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { bootCompleted(); } } } } } services/java/com/android/server/input/InputManagerService.java +50 −8 Original line number Original line Diff line number Diff line Loading @@ -113,6 +113,7 @@ public class InputManagerService extends IInputManager.Stub private final InputManagerHandler mHandler; private final InputManagerHandler mHandler; private WindowManagerCallbacks mWindowManagerCallbacks; private WindowManagerCallbacks mWindowManagerCallbacks; private WiredAccessoryCallbacks mWiredAccessoryCallbacks; private boolean mSystemReady; private boolean mSystemReady; private NotificationManager mNotificationManager; private NotificationManager mNotificationManager; Loading Loading @@ -213,17 +214,41 @@ public class InputManagerService extends IInputManager.Stub /** Scan code: Mouse / trackball button. */ /** Scan code: Mouse / trackball button. */ public static final int BTN_MOUSE = 0x110; public static final int BTN_MOUSE = 0x110; // Switch code values must match bionic/libc/kernel/common/linux/input.h /** Switch code: Lid switch. When set, lid is shut. */ /** Switch code: Lid switch. When set, lid is shut. */ public static final int SW_LID = 0x00; public static final int SW_LID = 0x00; /** Switch code: Keypad slide. When set, keyboard is exposed. */ /** Switch code: Keypad slide. When set, keyboard is exposed. */ public static final int SW_KEYPAD_SLIDE = 0x0a; public static final int SW_KEYPAD_SLIDE = 0x0a; /** Switch code: Headphone. When set, headphone is inserted. */ public static final int SW_HEADPHONE_INSERT = 0x02; /** Switch code: Microphone. When set, microphone is inserted. */ public static final int SW_MICROPHONE_INSERT = 0x04; /** Switch code: Headphone/Microphone Jack. When set, something is inserted. */ public static final int SW_JACK_PHYSICAL_INSERT = 0x07; public static final int SW_LID_BIT = 1 << SW_LID; public static final int SW_KEYPAD_SLIDE_BIT = 1 << SW_KEYPAD_SLIDE; public static final int SW_HEADPHONE_INSERT_BIT = 1 << SW_HEADPHONE_INSERT; public static final int SW_MICROPHONE_INSERT_BIT = 1 << SW_MICROPHONE_INSERT; public static final int SW_JACK_PHYSICAL_INSERT_BIT = 1 << SW_JACK_PHYSICAL_INSERT; public static final int SW_JACK_BITS = SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT | SW_JACK_PHYSICAL_INSERT_BIT; /** Whether to use the dev/input/event or uevent subsystem for the audio jack. */ final boolean mUseDevInputEventForAudioJack; public InputManagerService(Context context, Handler handler) { public InputManagerService(Context context, Handler handler) { this.mContext = context; this.mContext = context; this.mHandler = new InputManagerHandler(handler.getLooper()); this.mHandler = new InputManagerHandler(handler.getLooper()); Slog.i(TAG, "Initializing input manager"); mUseDevInputEventForAudioJack = context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack); Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack=" + mUseDevInputEventForAudioJack); mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue()); mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue()); } } Loading @@ -231,6 +256,10 @@ public class InputManagerService extends IInputManager.Stub mWindowManagerCallbacks = callbacks; mWindowManagerCallbacks = callbacks; } } public void setWiredAccessoryCallbacks(WiredAccessoryCallbacks callbacks) { mWiredAccessoryCallbacks = callbacks; } public void start() { public void start() { Slog.i(TAG, "Starting input manager"); Slog.i(TAG, "Starting input manager"); nativeStart(mPtr); nativeStart(mPtr); Loading Loading @@ -513,7 +542,7 @@ public class InputManagerService extends IInputManager.Stub /** /** * Gets information about the input device with the specified id. * Gets information about the input device with the specified id. * @param id The device id. * @param deviceId The device id. * @return The input device or null if not found. * @return The input device or null if not found. */ */ @Override // Binder call @Override // Binder call Loading Loading @@ -976,8 +1005,8 @@ public class InputManagerService extends IInputManager.Stub // Must be called on handler. // Must be called on handler. private void handleSwitchKeyboardLayout(int deviceId, int direction) { private void handleSwitchKeyboardLayout(int deviceId, int direction) { final InputDevice device = getInputDevice(deviceId); final InputDevice device = getInputDevice(deviceId); final String inputDeviceDescriptor = device.getDescriptor(); if (device != null) { if (device != null) { final String inputDeviceDescriptor = device.getDescriptor(); final boolean changed; final boolean changed; final String keyboardLayoutDescriptor; final String keyboardLayoutDescriptor; synchronized (mDataStore) { synchronized (mDataStore) { Loading Loading @@ -1214,6 +1243,7 @@ public class InputManagerService extends IInputManager.Stub } } // Called by the heartbeat to ensure locks are not held indefinitely (for deadlock detection). // Called by the heartbeat to ensure locks are not held indefinitely (for deadlock detection). @Override public void monitor() { public void monitor() { synchronized (mInputFilterLock) { } synchronized (mInputFilterLock) { } nativeMonitor(mPtr); nativeMonitor(mPtr); Loading Loading @@ -1244,10 +1274,15 @@ public class InputManagerService extends IInputManager.Stub + ", mask=" + Integer.toHexString(switchMask)); + ", mask=" + Integer.toHexString(switchMask)); } } if ((switchMask & (1 << SW_LID)) != 0) { if ((switchMask & SW_LID_BIT) != 0) { final boolean lidOpen = ((switchValues & (1 << SW_LID)) == 0); final boolean lidOpen = ((switchValues & SW_LID_BIT) == 0); mWindowManagerCallbacks.notifyLidSwitchChanged(whenNanos, lidOpen); mWindowManagerCallbacks.notifyLidSwitchChanged(whenNanos, lidOpen); } } if (mUseDevInputEventForAudioJack && (switchMask & SW_JACK_BITS) != 0) { mWiredAccessoryCallbacks.notifyWiredAccessoryChanged(whenNanos, switchValues, switchMask); } } } // Native callback. // Native callback. Loading Loading @@ -1431,7 +1466,6 @@ public class InputManagerService extends IInputManager.Stub return null; return null; } } /** /** * Callback interface implemented by the Window Manager. * Callback interface implemented by the Window Manager. */ */ Loading @@ -1458,6 +1492,13 @@ public class InputManagerService extends IInputManager.Stub public int getPointerLayer(); public int getPointerLayer(); } } /** * Callback interface implemented by WiredAccessoryObserver. */ public interface WiredAccessoryCallbacks { public void notifyWiredAccessoryChanged(long whenNanos, int switchValues, int switchMask); } /** /** * Private handler for the input manager. * Private handler for the input manager. */ */ Loading Loading @@ -1498,6 +1539,7 @@ public class InputManagerService extends IInputManager.Stub mDisconnected = true; mDisconnected = true; } } @Override public void sendInputEvent(InputEvent event, int policyFlags) { public void sendInputEvent(InputEvent event, int policyFlags) { if (event == null) { if (event == null) { throw new IllegalArgumentException("event must not be null"); throw new IllegalArgumentException("event must not be null"); Loading Loading
core/res/res/values/config.xml +4 −0 Original line number Original line Diff line number Diff line Loading @@ -960,4 +960,8 @@ --> --> <bool name="config_enableWifiDisplay">false</bool> <bool name="config_enableWifiDisplay">false</bool> <!-- 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> </resources> </resources>
core/res/res/values/symbols.xml +2 −1 Original line number Original line Diff line number Diff line Loading @@ -271,6 +271,7 @@ <java-symbol type="bool" name="config_enableScreenshotChord" /> <java-symbol type="bool" name="config_enableScreenshotChord" /> <java-symbol type="bool" name="config_bluetooth_default_profiles" /> <java-symbol type="bool" name="config_bluetooth_default_profiles" /> <java-symbol type="bool" name="config_enableWifiDisplay" /> <java-symbol type="bool" name="config_enableWifiDisplay" /> <java-symbol type="bool" name="config_useDevInputEventForAudioJack" /> <java-symbol type="integer" name="config_cursorWindowSize" /> <java-symbol type="integer" name="config_cursorWindowSize" /> <java-symbol type="integer" name="config_longPressOnPowerBehavior" /> <java-symbol type="integer" name="config_longPressOnPowerBehavior" /> Loading
services/java/com/android/server/SystemServer.java +4 −3 Original line number Original line Diff line number Diff line Loading @@ -631,11 +631,12 @@ class ServerThread extends Thread { } } try { try { Slog.i(TAG, "Wired Accessory Observer"); Slog.i(TAG, "Wired Accessory Manager"); // Listen for wired headset changes // Listen for wired headset changes new WiredAccessoryObserver(context); inputManager.setWiredAccessoryCallbacks( new WiredAccessoryManager(context, inputManager)); } catch (Throwable e) { } catch (Throwable e) { reportWtf("starting WiredAccessoryObserver", e); reportWtf("starting WiredAccessoryManager", e); } } try { try { Loading
services/java/com/android/server/WiredAccessoryObserver.java→services/java/com/android/server/WiredAccessoryManager.java +432 −0 Original line number Original line Diff line number Diff line Loading @@ -29,6 +29,15 @@ import android.os.UEventObserver; import android.util.Slog; import android.util.Slog; import android.media.AudioManager; import android.media.AudioManager; import android.util.Log; import android.util.Log; import android.view.InputDevice; import com.android.internal.R; import com.android.server.input.InputManagerService; import com.android.server.input.InputManagerService.WiredAccessoryCallbacks; import static com.android.server.input.InputManagerService.SW_HEADPHONE_INSERT; import static com.android.server.input.InputManagerService.SW_MICROPHONE_INSERT; import static com.android.server.input.InputManagerService.SW_HEADPHONE_INSERT_BIT; import static com.android.server.input.InputManagerService.SW_MICROPHONE_INSERT_BIT; import java.io.File; import java.io.File; import java.io.FileReader; import java.io.FileReader; Loading @@ -37,11 +46,14 @@ import java.util.ArrayList; import java.util.List; import java.util.List; /** /** * <p>WiredAccessoryObserver monitors for a wired headset on the main board or dock. * <p>WiredAccessoryManager monitors for a wired headset on the main board or dock using * both the InputManagerService notifyWiredAccessoryChanged interface and the UEventObserver * subsystem. */ */ final class WiredAccessoryObserver extends UEventObserver { final class WiredAccessoryManager implements WiredAccessoryCallbacks { private static final String TAG = WiredAccessoryObserver.class.getSimpleName(); private static final String TAG = WiredAccessoryManager.class.getSimpleName(); private static final boolean LOG = true; private static final boolean LOG = true; private static final int BIT_HEADSET = (1 << 0); private static final int BIT_HEADSET = (1 << 0); private static final int BIT_HEADSET_NO_MIC = (1 << 1); private static final int BIT_HEADSET_NO_MIC = (1 << 1); private static final int BIT_USB_HEADSET_ANLG = (1 << 2); private static final int BIT_USB_HEADSET_ANLG = (1 << 2); Loading @@ -51,94 +63,108 @@ final class WiredAccessoryObserver extends UEventObserver { BIT_USB_HEADSET_ANLG|BIT_USB_HEADSET_DGTL| BIT_USB_HEADSET_ANLG|BIT_USB_HEADSET_DGTL| BIT_HDMI_AUDIO); BIT_HDMI_AUDIO); private static final String NAME_H2W = "h2w"; private static final String NAME_USB_AUDIO = "usb_audio"; private static final String NAME_HDMI_AUDIO = "hdmi_audio"; private static final String NAME_HDMI = "hdmi"; private static final int MSG_NEW_DEVICE_STATE = 1; private final Object mLock = new Object(); private final Object mLock = new Object(); private final Context mContext; private final WakeLock mWakeLock; // held while there is a pending route change private final WakeLock mWakeLock; // held while there is a pending route change private final AudioManager mAudioManager; private final AudioManager mAudioManager; private final List<UEventInfo> mUEventInfo; private int mHeadsetState; private int mHeadsetState; private int mPrevHeadsetState; private String mHeadsetName; public WiredAccessoryObserver(Context context) { private int mSwitchValues; mContext = context; private final WiredAccessoryObserver mObserver; private final InputManagerService mInputManager; private final boolean mUseDevInputEventForAudioJack; public WiredAccessoryManager(Context context, InputManagerService inputManager) { PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WiredAccessoryObserver"); mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WiredAccessoryManager"); mWakeLock.setReferenceCounted(false); mWakeLock.setReferenceCounted(false); mAudioManager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE); mAudioManager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE); mInputManager = inputManager; mUEventInfo = makeObservedUEventList(); mUseDevInputEventForAudioJack = context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack); context.registerReceiver(new BootCompletedReceiver(), mObserver = new WiredAccessoryObserver(); new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null); } context.registerReceiver(new BroadcastReceiver() { @Override @Override public void onUEvent(UEventObserver.UEvent event) { public void onReceive(Context ctx, Intent intent) { if (LOG) Slog.v(TAG, "Headset UEVENT: " + event.toString()); bootCompleted(); } }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null); } try { private void bootCompleted() { String devPath = event.get("DEVPATH"); if (mUseDevInputEventForAudioJack) { String name = event.get("SWITCH_NAME"); int switchValues = 0; int state = Integer.parseInt(event.get("SWITCH_STATE")); if (mInputManager.getSwitchState(-1, InputDevice.SOURCE_ANY, SW_HEADPHONE_INSERT) == 1) { synchronized (mLock) { switchValues |= SW_HEADPHONE_INSERT_BIT; updateStateLocked(devPath, name, state); } } } catch (NumberFormatException e) { if (mInputManager.getSwitchState(-1, InputDevice.SOURCE_ANY, SW_MICROPHONE_INSERT) == 1) { Slog.e(TAG, "Could not parse switch state from event " + event); switchValues |= SW_MICROPHONE_INSERT_BIT; } } notifyWiredAccessoryChanged(0, switchValues, SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT); } } private void bootCompleted() { mObserver.init(); } @Override public void notifyWiredAccessoryChanged(long whenNanos, int switchValues, int switchMask) { if (LOG) Slog.v(TAG, "notifyWiredAccessoryChanged: when=" + whenNanos + " bits=" + switchCodeToString(switchValues, switchMask) + " mask=" + Integer.toHexString(switchMask)); synchronized (mLock) { synchronized (mLock) { char[] buffer = new char[1024]; int headset; mPrevHeadsetState = mHeadsetState; mSwitchValues = (mSwitchValues & ~switchMask) | switchValues; switch (mSwitchValues & (SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT)) { case 0: headset = 0; break; if (LOG) Slog.v(TAG, "init()"); case SW_HEADPHONE_INSERT_BIT: headset = BIT_HEADSET_NO_MIC; break; for (int i = 0; i < mUEventInfo.size(); ++i) { case SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT: UEventInfo uei = mUEventInfo.get(i); headset = BIT_HEADSET; try { break; 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) { case SW_MICROPHONE_INSERT_BIT: updateStateLocked(uei.getDevPath(), uei.getDevName(), curState); headset = BIT_HEADSET; } break; } catch (FileNotFoundException e) { Slog.w(TAG, uei.getSwitchStatePath() + " not found while attempting to determine initial switch state"); } catch (Exception e) { Slog.e(TAG, "" , e); } } } // At any given time accessories could be inserted default: // one on the board, one on the dock and one on HDMI: headset = 0; // observe three UEVENTs break; for (int i = 0; i < mUEventInfo.size(); ++i) { UEventInfo uei = mUEventInfo.get(i); startObserving("DEVPATH="+uei.getDevPath()); } } } private void updateStateLocked(String devPath, String name, int state) { updateLocked(NAME_H2W, headset); 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; } } } } } /** * Compare the existing headset state with the new state and pass along accordingly. Note * that this only supports a single headset at a time. Inserting both a usb and jacked headset * results in support for the last one plugged in. Similarly, unplugging either is seen as * unplugging all. * * @param newName One of the NAME_xxx variables defined above. * @param newState 0 or one of the BIT_xxx variables defined above. */ private void updateLocked(String newName, int newState) { private void updateLocked(String newName, int newState) { // Retain only relevant bits // Retain only relevant bits int headsetState = newState & SUPPORTED_HEADSETS; int headsetState = newState & SUPPORTED_HEADSETS; Loading @@ -147,19 +173,27 @@ final class WiredAccessoryObserver extends UEventObserver { int h2w_headset = headsetState & (BIT_HEADSET | BIT_HEADSET_NO_MIC); int h2w_headset = headsetState & (BIT_HEADSET | BIT_HEADSET_NO_MIC); boolean h2wStateChange = true; boolean h2wStateChange = true; boolean usbStateChange = true; boolean usbStateChange = true; if (LOG) Slog.v(TAG, "newName=" + newName + " newState=" + newState + " headsetState=" + headsetState + " prev headsetState=" + mHeadsetState); if (mHeadsetState == headsetState) { Log.e(TAG, "No state change."); return; } // reject all suspect transitions: only accept state changes from: // reject all suspect transitions: only accept state changes from: // - a: 0 heaset to 1 headset // - a: 0 headset to 1 headset // - b: 1 headset to 0 headset // - b: 1 headset to 0 headset if (LOG) Slog.v(TAG, "newState = "+newState+", headsetState = "+headsetState+"," if (h2w_headset == (BIT_HEADSET | BIT_HEADSET_NO_MIC)) { + "mHeadsetState = "+mHeadsetState); Log.e(TAG, "Invalid combination, unsetting h2w flag"); if (mHeadsetState == headsetState || ((h2w_headset & (h2w_headset - 1)) != 0)) { Log.e(TAG, "unsetting h2w flag"); h2wStateChange = false; h2wStateChange = false; } } // - c: 0 usb headset to 1 usb headset // - c: 0 usb headset to 1 usb headset // - d: 1 usb headset to 0 usb headset // - d: 1 usb headset to 0 usb headset if ((usb_headset_anlg >> 2) == 1 && (usb_headset_dgtl >> 3) == 1) { if (usb_headset_anlg == BIT_USB_HEADSET_ANLG && usb_headset_dgtl == BIT_USB_HEADSET_DGTL) { Log.e(TAG, "unsetting usb flag"); Log.e(TAG, "Invalid combination, unsetting usb flag"); usbStateChange = false; usbStateChange = false; } } if (!h2wStateChange && !usbStateChange) { if (!h2wStateChange && !usbStateChange) { Loading @@ -167,16 +201,26 @@ final class WiredAccessoryObserver extends UEventObserver { return; return; } } mHeadsetName = newName; mPrevHeadsetState = mHeadsetState; mHeadsetState = headsetState; mWakeLock.acquire(); mWakeLock.acquire(); Message msg = mHandler.obtainMessage(0, mHeadsetState, mPrevHeadsetState, mHeadsetName); Message msg = mHandler.obtainMessage(MSG_NEW_DEVICE_STATE, headsetState, mHeadsetState, newName); mHandler.sendMessage(msg); mHandler.sendMessage(msg); mHeadsetState = headsetState; } } private final Handler mHandler = new Handler(Looper.myLooper(), null, true) { @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_NEW_DEVICE_STATE: setDevicesState(msg.arg1, msg.arg2, (String)msg.obj); mWakeLock.release(); } } }; private void setDevicesState( private void setDevicesState( int headsetState, int prevHeadsetState, String headsetName) { int headsetState, int prevHeadsetState, String headsetName) { synchronized (mLock) { synchronized (mLock) { Loading Loading @@ -224,20 +268,77 @@ final class WiredAccessoryObserver extends UEventObserver { } } } } private static List<UEventInfo> makeObservedUEventList() { private String switchCodeToString(int switchValues, int switchMask) { StringBuffer sb = new StringBuffer(); if ((switchMask & SW_HEADPHONE_INSERT_BIT) != 0 && (switchValues & SW_HEADPHONE_INSERT_BIT) != 0) { sb.append("SW_HEADPHONE_INSERT "); } if ((switchMask & SW_MICROPHONE_INSERT_BIT) != 0 && (switchValues & SW_MICROPHONE_INSERT_BIT) != 0) { sb.append("SW_MICROPHONE_INSERT"); } return sb.toString(); } class WiredAccessoryObserver extends UEventObserver { private final List<UEventInfo> mUEventInfo; public WiredAccessoryObserver() { mUEventInfo = makeObservedUEventList(); } void init() { synchronized (mLock) { if (LOG) Slog.v(TAG, "init()"); char[] buffer = new char[1024]; 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); } } } // 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()); } } private List<UEventInfo> makeObservedUEventList() { List<UEventInfo> retVal = new ArrayList<UEventInfo>(); List<UEventInfo> retVal = new ArrayList<UEventInfo>(); UEventInfo uei; UEventInfo uei; // Monitor h2w // Monitor h2w uei = new UEventInfo("h2w", BIT_HEADSET, BIT_HEADSET_NO_MIC); if (!mUseDevInputEventForAudioJack) { uei = new UEventInfo(NAME_H2W, BIT_HEADSET, BIT_HEADSET_NO_MIC); if (uei.checkSwitchExists()) { if (uei.checkSwitchExists()) { retVal.add(uei); retVal.add(uei); } else { } else { Slog.w(TAG, "This kernel does not have wired headset support"); Slog.w(TAG, "This kernel does not have wired headset support"); } } } // Monitor USB // Monitor USB uei = new UEventInfo("usb_audio", BIT_USB_HEADSET_ANLG, BIT_USB_HEADSET_DGTL); uei = new UEventInfo(NAME_USB_AUDIO, BIT_USB_HEADSET_ANLG, BIT_USB_HEADSET_DGTL); if (uei.checkSwitchExists()) { if (uei.checkSwitchExists()) { retVal.add(uei); retVal.add(uei); } else { } else { Loading @@ -246,17 +347,17 @@ final class WiredAccessoryObserver extends UEventObserver { // Monitor HDMI // Monitor HDMI // // // If the kernel has support for the "hdmi_audio" switch, use that. It will be signalled // If the kernel has support for the "hdmi_audio" switch, use that. It will be // only when the HDMI driver has a video mode configured, and the downstream sink indicates // signalled only when the HDMI driver has a video mode configured, and the downstream // support for audio in its EDID. // 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" // If the kernel does not have an "hdmi_audio" switch, just fall back on the older // switch instead. // "hdmi" switch instead. uei = new UEventInfo("hdmi_audio", BIT_HDMI_AUDIO, 0); uei = new UEventInfo(NAME_HDMI_AUDIO, BIT_HDMI_AUDIO, 0); if (uei.checkSwitchExists()) { if (uei.checkSwitchExists()) { retVal.add(uei); retVal.add(uei); } else { } else { uei = new UEventInfo("hdmi", BIT_HDMI_AUDIO, 0); uei = new UEventInfo(NAME_HDMI, BIT_HDMI_AUDIO, 0); if (uei.checkSwitchExists()) { if (uei.checkSwitchExists()) { retVal.add(uei); retVal.add(uei); } else { } else { Loading @@ -267,15 +368,33 @@ final class WiredAccessoryObserver extends UEventObserver { return retVal; return retVal; } } private final Handler mHandler = new Handler(Looper.myLooper(), null, true) { @Override @Override public void handleMessage(Message msg) { public void onUEvent(UEventObserver.UEvent event) { setDevicesState(msg.arg1, msg.arg2, (String)msg.obj); if (LOG) Slog.v(TAG, "Headset UEVENT: " + event.toString()); mWakeLock.release(); try { String devPath = event.get("DEVPATH"); String name = event.get("SWITCH_NAME"); int state = Integer.parseInt(event.get("SWITCH_STATE")); synchronized (mLock) { updateStateLocked(devPath, name, state); } } catch (NumberFormatException e) { Slog.e(TAG, "Could not parse switch state from event " + event); } } 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 static final class UEventInfo { private final class UEventInfo { private final String mDevName; private final String mDevName; private final int mState1Bits; private final int mState1Bits; private final int mState2Bits; private final int mState2Bits; Loading @@ -298,7 +417,7 @@ final class WiredAccessoryObserver extends UEventObserver { public boolean checkSwitchExists() { public boolean checkSwitchExists() { File f = new File(getSwitchStatePath()); File f = new File(getSwitchStatePath()); return ((null != f) && f.exists()); return f.exists(); } } public int computeNewHeadsetState(int headsetState, int switchState) { public int computeNewHeadsetState(int headsetState, int switchState) { Loading @@ -309,11 +428,5 @@ final class WiredAccessoryObserver extends UEventObserver { return ((headsetState & preserveMask) | setBits); return ((headsetState & preserveMask) | setBits); } } } } private final class BootCompletedReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { bootCompleted(); } } } } }
services/java/com/android/server/input/InputManagerService.java +50 −8 Original line number Original line Diff line number Diff line Loading @@ -113,6 +113,7 @@ public class InputManagerService extends IInputManager.Stub private final InputManagerHandler mHandler; private final InputManagerHandler mHandler; private WindowManagerCallbacks mWindowManagerCallbacks; private WindowManagerCallbacks mWindowManagerCallbacks; private WiredAccessoryCallbacks mWiredAccessoryCallbacks; private boolean mSystemReady; private boolean mSystemReady; private NotificationManager mNotificationManager; private NotificationManager mNotificationManager; Loading Loading @@ -213,17 +214,41 @@ public class InputManagerService extends IInputManager.Stub /** Scan code: Mouse / trackball button. */ /** Scan code: Mouse / trackball button. */ public static final int BTN_MOUSE = 0x110; public static final int BTN_MOUSE = 0x110; // Switch code values must match bionic/libc/kernel/common/linux/input.h /** Switch code: Lid switch. When set, lid is shut. */ /** Switch code: Lid switch. When set, lid is shut. */ public static final int SW_LID = 0x00; public static final int SW_LID = 0x00; /** Switch code: Keypad slide. When set, keyboard is exposed. */ /** Switch code: Keypad slide. When set, keyboard is exposed. */ public static final int SW_KEYPAD_SLIDE = 0x0a; public static final int SW_KEYPAD_SLIDE = 0x0a; /** Switch code: Headphone. When set, headphone is inserted. */ public static final int SW_HEADPHONE_INSERT = 0x02; /** Switch code: Microphone. When set, microphone is inserted. */ public static final int SW_MICROPHONE_INSERT = 0x04; /** Switch code: Headphone/Microphone Jack. When set, something is inserted. */ public static final int SW_JACK_PHYSICAL_INSERT = 0x07; public static final int SW_LID_BIT = 1 << SW_LID; public static final int SW_KEYPAD_SLIDE_BIT = 1 << SW_KEYPAD_SLIDE; public static final int SW_HEADPHONE_INSERT_BIT = 1 << SW_HEADPHONE_INSERT; public static final int SW_MICROPHONE_INSERT_BIT = 1 << SW_MICROPHONE_INSERT; public static final int SW_JACK_PHYSICAL_INSERT_BIT = 1 << SW_JACK_PHYSICAL_INSERT; public static final int SW_JACK_BITS = SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT | SW_JACK_PHYSICAL_INSERT_BIT; /** Whether to use the dev/input/event or uevent subsystem for the audio jack. */ final boolean mUseDevInputEventForAudioJack; public InputManagerService(Context context, Handler handler) { public InputManagerService(Context context, Handler handler) { this.mContext = context; this.mContext = context; this.mHandler = new InputManagerHandler(handler.getLooper()); this.mHandler = new InputManagerHandler(handler.getLooper()); Slog.i(TAG, "Initializing input manager"); mUseDevInputEventForAudioJack = context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack); Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack=" + mUseDevInputEventForAudioJack); mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue()); mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue()); } } Loading @@ -231,6 +256,10 @@ public class InputManagerService extends IInputManager.Stub mWindowManagerCallbacks = callbacks; mWindowManagerCallbacks = callbacks; } } public void setWiredAccessoryCallbacks(WiredAccessoryCallbacks callbacks) { mWiredAccessoryCallbacks = callbacks; } public void start() { public void start() { Slog.i(TAG, "Starting input manager"); Slog.i(TAG, "Starting input manager"); nativeStart(mPtr); nativeStart(mPtr); Loading Loading @@ -513,7 +542,7 @@ public class InputManagerService extends IInputManager.Stub /** /** * Gets information about the input device with the specified id. * Gets information about the input device with the specified id. * @param id The device id. * @param deviceId The device id. * @return The input device or null if not found. * @return The input device or null if not found. */ */ @Override // Binder call @Override // Binder call Loading Loading @@ -976,8 +1005,8 @@ public class InputManagerService extends IInputManager.Stub // Must be called on handler. // Must be called on handler. private void handleSwitchKeyboardLayout(int deviceId, int direction) { private void handleSwitchKeyboardLayout(int deviceId, int direction) { final InputDevice device = getInputDevice(deviceId); final InputDevice device = getInputDevice(deviceId); final String inputDeviceDescriptor = device.getDescriptor(); if (device != null) { if (device != null) { final String inputDeviceDescriptor = device.getDescriptor(); final boolean changed; final boolean changed; final String keyboardLayoutDescriptor; final String keyboardLayoutDescriptor; synchronized (mDataStore) { synchronized (mDataStore) { Loading Loading @@ -1214,6 +1243,7 @@ public class InputManagerService extends IInputManager.Stub } } // Called by the heartbeat to ensure locks are not held indefinitely (for deadlock detection). // Called by the heartbeat to ensure locks are not held indefinitely (for deadlock detection). @Override public void monitor() { public void monitor() { synchronized (mInputFilterLock) { } synchronized (mInputFilterLock) { } nativeMonitor(mPtr); nativeMonitor(mPtr); Loading Loading @@ -1244,10 +1274,15 @@ public class InputManagerService extends IInputManager.Stub + ", mask=" + Integer.toHexString(switchMask)); + ", mask=" + Integer.toHexString(switchMask)); } } if ((switchMask & (1 << SW_LID)) != 0) { if ((switchMask & SW_LID_BIT) != 0) { final boolean lidOpen = ((switchValues & (1 << SW_LID)) == 0); final boolean lidOpen = ((switchValues & SW_LID_BIT) == 0); mWindowManagerCallbacks.notifyLidSwitchChanged(whenNanos, lidOpen); mWindowManagerCallbacks.notifyLidSwitchChanged(whenNanos, lidOpen); } } if (mUseDevInputEventForAudioJack && (switchMask & SW_JACK_BITS) != 0) { mWiredAccessoryCallbacks.notifyWiredAccessoryChanged(whenNanos, switchValues, switchMask); } } } // Native callback. // Native callback. Loading Loading @@ -1431,7 +1466,6 @@ public class InputManagerService extends IInputManager.Stub return null; return null; } } /** /** * Callback interface implemented by the Window Manager. * Callback interface implemented by the Window Manager. */ */ Loading @@ -1458,6 +1492,13 @@ public class InputManagerService extends IInputManager.Stub public int getPointerLayer(); public int getPointerLayer(); } } /** * Callback interface implemented by WiredAccessoryObserver. */ public interface WiredAccessoryCallbacks { public void notifyWiredAccessoryChanged(long whenNanos, int switchValues, int switchMask); } /** /** * Private handler for the input manager. * Private handler for the input manager. */ */ Loading Loading @@ -1498,6 +1539,7 @@ public class InputManagerService extends IInputManager.Stub mDisconnected = true; mDisconnected = true; } } @Override public void sendInputEvent(InputEvent event, int policyFlags) { public void sendInputEvent(InputEvent event, int policyFlags) { if (event == null) { if (event == null) { throw new IllegalArgumentException("event must not be null"); throw new IllegalArgumentException("event must not be null"); Loading