12f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner/* 22f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner * Copyright (C) 2008 The Android Open Source Project 32f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner * 42f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner * Licensed under the Apache License, Version 2.0 (the "License"); 52f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner * you may not use this file except in compliance with the License. 62f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner * You may obtain a copy of the License at 72f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner * 82f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner * http://www.apache.org/licenses/LICENSE-2.0 92f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner * 102f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner * Unless required by applicable law or agreed to in writing, software 112f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner * distributed under the License is distributed on an "AS IS" BASIS, 122f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 132f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner * See the License for the specific language governing permissions and 142f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner * limitations under the License. 152f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner */ 162f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 172f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautnerpackage com.android.server; 182f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 192f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautnerimport android.content.BroadcastReceiver; 202f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautnerimport android.content.Context; 212f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautnerimport android.content.Intent; 222f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautnerimport android.content.IntentFilter; 232f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautnerimport android.os.Handler; 242f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautnerimport android.os.Looper; 252f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautnerimport android.os.Message; 262f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautnerimport android.os.PowerManager; 272f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautnerimport android.os.PowerManager.WakeLock; 282f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautnerimport android.os.UEventObserver; 292f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautnerimport android.util.Slog; 302f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautnerimport android.media.AudioManager; 312f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautnerimport android.util.Log; 322f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautnerimport android.view.InputDevice; 332f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 342f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautnerimport com.android.internal.R; 352f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautnerimport com.android.server.input.InputManagerService; 362f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautnerimport com.android.server.input.InputManagerService.WiredAccessoryCallbacks; 372f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautnerimport static com.android.server.input.InputManagerService.SW_HEADPHONE_INSERT; 382f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautnerimport static com.android.server.input.InputManagerService.SW_MICROPHONE_INSERT; 392f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautnerimport static com.android.server.input.InputManagerService.SW_HEADPHONE_INSERT_BIT; 402f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautnerimport static com.android.server.input.InputManagerService.SW_MICROPHONE_INSERT_BIT; 412f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 422f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautnerimport java.io.File; 432f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautnerimport java.io.FileReader; 442f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautnerimport java.io.FileNotFoundException; 452f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautnerimport java.util.ArrayList; 462f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautnerimport java.util.List; 472f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 482f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner/** 492f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner * <p>WiredAccessoryManager monitors for a wired headset on the main board or dock using 502f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner * both the InputManagerService notifyWiredAccessoryChanged interface and the UEventObserver 512f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner * subsystem. 522f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner */ 532f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautnerfinal class WiredAccessoryManager implements WiredAccessoryCallbacks { 542f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner private static final String TAG = WiredAccessoryManager.class.getSimpleName(); 552f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner private static final boolean LOG = true; 562f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 572f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner private static final int BIT_HEADSET = (1 << 0); 582f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner private static final int BIT_HEADSET_NO_MIC = (1 << 1); 592f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner private static final int BIT_USB_HEADSET_ANLG = (1 << 2); 602f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner private static final int BIT_USB_HEADSET_DGTL = (1 << 3); 612f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner private static final int BIT_HDMI_AUDIO = (1 << 4); 622f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner private static final int SUPPORTED_HEADSETS = (BIT_HEADSET|BIT_HEADSET_NO_MIC| 632f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner BIT_USB_HEADSET_ANLG|BIT_USB_HEADSET_DGTL| 642f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner BIT_HDMI_AUDIO); 652f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 662f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner private static final String NAME_H2W = "h2w"; 672f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner private static final String NAME_USB_AUDIO = "usb_audio"; 682f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner private static final String NAME_HDMI_AUDIO = "hdmi_audio"; 692f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner private static final String NAME_HDMI = "hdmi"; 702f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 712f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner private static final int MSG_NEW_DEVICE_STATE = 1; 722f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 732f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner private final Object mLock = new Object(); 742f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 752f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner private final WakeLock mWakeLock; // held while there is a pending route change 762f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner private final AudioManager mAudioManager; 772f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 782f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner private int mHeadsetState; 792f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 802f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner private int mSwitchValues; 812f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 822f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner private final WiredAccessoryObserver mObserver; 832f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner private final InputManagerService mInputManager; 842f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 852f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner private final boolean mUseDevInputEventForAudioJack; 862f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 872f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner public WiredAccessoryManager(Context context, InputManagerService inputManager) { 882f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); 892f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WiredAccessoryManager"); 902f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner mWakeLock.setReferenceCounted(false); 912f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner mAudioManager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE); 922f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner mInputManager = inputManager; 932f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 942f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner mUseDevInputEventForAudioJack = 952f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack); 962f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 972f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner mObserver = new WiredAccessoryObserver(); 982f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 992f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner context.registerReceiver(new BroadcastReceiver() { 1002f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner @Override 1012f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner public void onReceive(Context ctx, Intent intent) { 1022f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner bootCompleted(); 1032f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } 1042f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner }, 1052f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null); 1062f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } 1072f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 1082f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner private void bootCompleted() { 1092f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner if (mUseDevInputEventForAudioJack) { 1102f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner int switchValues = 0; 1112f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner if (mInputManager.getSwitchState(-1, InputDevice.SOURCE_ANY, SW_HEADPHONE_INSERT) == 1) { 1122f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner switchValues |= SW_HEADPHONE_INSERT_BIT; 1132f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } 1142f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner if (mInputManager.getSwitchState(-1, InputDevice.SOURCE_ANY, SW_MICROPHONE_INSERT) == 1) { 1152f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner switchValues |= SW_MICROPHONE_INSERT_BIT; 1162f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } 1172f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner notifyWiredAccessoryChanged(0, switchValues, 1182f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT); 1192f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } 1202f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 1212f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner mObserver.init(); 1222f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } 1232f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 1242f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner @Override 1252f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner public void notifyWiredAccessoryChanged(long whenNanos, int switchValues, int switchMask) { 1262f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner if (LOG) Slog.v(TAG, "notifyWiredAccessoryChanged: when=" + whenNanos 1272f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner + " bits=" + switchCodeToString(switchValues, switchMask) 1282f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner + " mask=" + Integer.toHexString(switchMask)); 1292f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 1302f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner synchronized (mLock) { 1312f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner int headset; 1322f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner mSwitchValues = (mSwitchValues & ~switchMask) | switchValues; 1332f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner switch (mSwitchValues & (SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT)) { 1342f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner case 0: 1352f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner headset = 0; 1362f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner break; 1372f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 1382f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner case SW_HEADPHONE_INSERT_BIT: 1392f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner headset = BIT_HEADSET_NO_MIC; 1402f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner break; 1412f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 1422f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner case SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT: 1432f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner headset = BIT_HEADSET; 1442f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner break; 1452f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 1462f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner case SW_MICROPHONE_INSERT_BIT: 1472f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner headset = BIT_HEADSET; 1482f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner break; 1492f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 1502f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner default: 1512f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner headset = 0; 1522f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner break; 1532f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } 1542f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 1559e6e8355f8d7bd1856e69cb8965087a00f1792bdEric Laurent updateLocked(NAME_H2W, (mHeadsetState & ~(BIT_HEADSET | BIT_HEADSET_NO_MIC)) | headset); 1562f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } 1572f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } 1582f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 1592f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner /** 1602f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner * Compare the existing headset state with the new state and pass along accordingly. Note 1612f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner * that this only supports a single headset at a time. Inserting both a usb and jacked headset 1622f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner * results in support for the last one plugged in. Similarly, unplugging either is seen as 1632f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner * unplugging all. 1642f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner * 1652f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner * @param newName One of the NAME_xxx variables defined above. 1662f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner * @param newState 0 or one of the BIT_xxx variables defined above. 1672f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner */ 1682f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner private void updateLocked(String newName, int newState) { 1692f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner // Retain only relevant bits 1702f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner int headsetState = newState & SUPPORTED_HEADSETS; 1712f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner int usb_headset_anlg = headsetState & BIT_USB_HEADSET_ANLG; 1722f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner int usb_headset_dgtl = headsetState & BIT_USB_HEADSET_DGTL; 1732f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner int h2w_headset = headsetState & (BIT_HEADSET | BIT_HEADSET_NO_MIC); 1742f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner boolean h2wStateChange = true; 1752f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner boolean usbStateChange = true; 1762f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner if (LOG) Slog.v(TAG, "newName=" + newName 1772f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner + " newState=" + newState 1782f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner + " headsetState=" + headsetState 1792f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner + " prev headsetState=" + mHeadsetState); 1802f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 1812f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner if (mHeadsetState == headsetState) { 1822f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner Log.e(TAG, "No state change."); 1832f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner return; 1842f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } 1852f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 1862f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner // reject all suspect transitions: only accept state changes from: 1872f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner // - a: 0 headset to 1 headset 1882f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner // - b: 1 headset to 0 headset 1892f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner if (h2w_headset == (BIT_HEADSET | BIT_HEADSET_NO_MIC)) { 1902f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner Log.e(TAG, "Invalid combination, unsetting h2w flag"); 1912f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner h2wStateChange = false; 1922f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } 1932f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner // - c: 0 usb headset to 1 usb headset 1942f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner // - d: 1 usb headset to 0 usb headset 1952f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner if (usb_headset_anlg == BIT_USB_HEADSET_ANLG && usb_headset_dgtl == BIT_USB_HEADSET_DGTL) { 1962f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner Log.e(TAG, "Invalid combination, unsetting usb flag"); 1972f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner usbStateChange = false; 1982f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } 1992f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner if (!h2wStateChange && !usbStateChange) { 2002f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner Log.e(TAG, "invalid transition, returning ..."); 2012f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner return; 2022f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } 2032f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 2042f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner mWakeLock.acquire(); 2052f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 2062f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner Message msg = mHandler.obtainMessage(MSG_NEW_DEVICE_STATE, headsetState, 2072f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner mHeadsetState, newName); 2082f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner mHandler.sendMessage(msg); 2092f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 2102f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner mHeadsetState = headsetState; 2112f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } 2122f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 2132f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner private final Handler mHandler = new Handler(Looper.myLooper(), null, true) { 2142f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner @Override 2152f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner public void handleMessage(Message msg) { 2162f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner switch (msg.what) { 2172f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner case MSG_NEW_DEVICE_STATE: 2182f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner setDevicesState(msg.arg1, msg.arg2, (String)msg.obj); 2192f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner mWakeLock.release(); 2202f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } 2212f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } 2222f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner }; 2232f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 2242f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner private void setDevicesState( 2252f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner int headsetState, int prevHeadsetState, String headsetName) { 2262f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner synchronized (mLock) { 2272f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner int allHeadsets = SUPPORTED_HEADSETS; 2282f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner for (int curHeadset = 1; allHeadsets != 0; curHeadset <<= 1) { 2292f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner if ((curHeadset & allHeadsets) != 0) { 2302f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner setDeviceStateLocked(curHeadset, headsetState, prevHeadsetState, headsetName); 2312f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner allHeadsets &= ~curHeadset; 2322f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } 2332f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } 2342f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } 2352f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } 2362f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 2372f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner private void setDeviceStateLocked(int headset, 2382f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner int headsetState, int prevHeadsetState, String headsetName) { 2392f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner if ((headsetState & headset) != (prevHeadsetState & headset)) { 2402f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner int device; 2412f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner int state; 2422f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 2432f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner if ((headsetState & headset) != 0) { 2442f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner state = 1; 2452f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } else { 2462f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner state = 0; 2472f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } 2482f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 2492f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner if (headset == BIT_HEADSET) { 2502f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner device = AudioManager.DEVICE_OUT_WIRED_HEADSET; 2512f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } else if (headset == BIT_HEADSET_NO_MIC){ 2522f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner device = AudioManager.DEVICE_OUT_WIRED_HEADPHONE; 2532f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } else if (headset == BIT_USB_HEADSET_ANLG) { 2542f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner device = AudioManager.DEVICE_OUT_ANLG_DOCK_HEADSET; 2552f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } else if (headset == BIT_USB_HEADSET_DGTL) { 2562f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner device = AudioManager.DEVICE_OUT_DGTL_DOCK_HEADSET; 2572f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } else if (headset == BIT_HDMI_AUDIO) { 2582f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner device = AudioManager.DEVICE_OUT_AUX_DIGITAL; 2592f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } else { 2602f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner Slog.e(TAG, "setDeviceState() invalid headset type: "+headset); 2612f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner return; 2622f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } 2632f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 2642f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner if (LOG) 2652f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner Slog.v(TAG, "device "+headsetName+((state == 1) ? " connected" : " disconnected")); 2662f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 2672f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner mAudioManager.setWiredDeviceConnectionState(device, state, headsetName); 2682f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } 2692f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } 2702f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 2712f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner private String switchCodeToString(int switchValues, int switchMask) { 2722f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner StringBuffer sb = new StringBuffer(); 2732f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner if ((switchMask & SW_HEADPHONE_INSERT_BIT) != 0 && 2742f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner (switchValues & SW_HEADPHONE_INSERT_BIT) != 0) { 2752f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner sb.append("SW_HEADPHONE_INSERT "); 2762f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } 2772f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner if ((switchMask & SW_MICROPHONE_INSERT_BIT) != 0 && 2782f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner (switchValues & SW_MICROPHONE_INSERT_BIT) != 0) { 2792f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner sb.append("SW_MICROPHONE_INSERT"); 2802f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } 2812f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner return sb.toString(); 2822f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } 2832f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 2842f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner class WiredAccessoryObserver extends UEventObserver { 2852f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner private final List<UEventInfo> mUEventInfo; 2862f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 2872f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner public WiredAccessoryObserver() { 2882f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner mUEventInfo = makeObservedUEventList(); 2892f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } 2902f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 2912f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner void init() { 2922f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner synchronized (mLock) { 2932f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner if (LOG) Slog.v(TAG, "init()"); 2942f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner char[] buffer = new char[1024]; 2952f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 2962f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner for (int i = 0; i < mUEventInfo.size(); ++i) { 2972f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner UEventInfo uei = mUEventInfo.get(i); 2982f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner try { 2992f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner int curState; 3002f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner FileReader file = new FileReader(uei.getSwitchStatePath()); 3012f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner int len = file.read(buffer, 0, 1024); 3022f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner file.close(); 3032f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner curState = Integer.valueOf((new String(buffer, 0, len)).trim()); 3042f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 3052f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner if (curState > 0) { 3062f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner updateStateLocked(uei.getDevPath(), uei.getDevName(), curState); 3072f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } 3082f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } catch (FileNotFoundException e) { 3092f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner Slog.w(TAG, uei.getSwitchStatePath() + 3102f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner " not found while attempting to determine initial switch state"); 3112f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } catch (Exception e) { 3122f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner Slog.e(TAG, "" , e); 3132f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } 3142f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } 3152f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } 3162f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 3172f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner // At any given time accessories could be inserted 3182f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner // one on the board, one on the dock and one on HDMI: 3192f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner // observe three UEVENTs 3202f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner for (int i = 0; i < mUEventInfo.size(); ++i) { 3212f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner UEventInfo uei = mUEventInfo.get(i); 3222f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner startObserving("DEVPATH="+uei.getDevPath()); 3232f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } 3242f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } 3252f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 3262f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner private List<UEventInfo> makeObservedUEventList() { 3272f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner List<UEventInfo> retVal = new ArrayList<UEventInfo>(); 3282f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner UEventInfo uei; 3292f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 3302f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner // Monitor h2w 3312f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner if (!mUseDevInputEventForAudioJack) { 3322f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner uei = new UEventInfo(NAME_H2W, BIT_HEADSET, BIT_HEADSET_NO_MIC); 3332f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner if (uei.checkSwitchExists()) { 3342f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner retVal.add(uei); 3352f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } else { 3362f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner Slog.w(TAG, "This kernel does not have wired headset support"); 3372f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } 3382f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } 3392f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 3402f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner // Monitor USB 3412f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner uei = new UEventInfo(NAME_USB_AUDIO, BIT_USB_HEADSET_ANLG, BIT_USB_HEADSET_DGTL); 3422f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner if (uei.checkSwitchExists()) { 3432f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner retVal.add(uei); 3442f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } else { 3452f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner Slog.w(TAG, "This kernel does not have usb audio support"); 3462f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } 3472f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 3482f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner // Monitor HDMI 3492f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner // 3502f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner // If the kernel has support for the "hdmi_audio" switch, use that. It will be 3512f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner // signalled only when the HDMI driver has a video mode configured, and the downstream 3522f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner // sink indicates support for audio in its EDID. 3532f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner // 3542f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner // If the kernel does not have an "hdmi_audio" switch, just fall back on the older 3552f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner // "hdmi" switch instead. 3562f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner uei = new UEventInfo(NAME_HDMI_AUDIO, BIT_HDMI_AUDIO, 0); 3572f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner if (uei.checkSwitchExists()) { 3582f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner retVal.add(uei); 3592f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } else { 3602f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner uei = new UEventInfo(NAME_HDMI, BIT_HDMI_AUDIO, 0); 3612f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner if (uei.checkSwitchExists()) { 3622f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner retVal.add(uei); 3632f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } else { 3642f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner Slog.w(TAG, "This kernel does not have HDMI audio support"); 3652f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } 3662f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } 3672f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 3682f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner return retVal; 3692f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } 3702f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 3712f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner @Override 3722f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner public void onUEvent(UEventObserver.UEvent event) { 3732f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner if (LOG) Slog.v(TAG, "Headset UEVENT: " + event.toString()); 3742f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 3752f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner try { 3762f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner String devPath = event.get("DEVPATH"); 3772f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner String name = event.get("SWITCH_NAME"); 3782f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner int state = Integer.parseInt(event.get("SWITCH_STATE")); 3792f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner synchronized (mLock) { 3802f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner updateStateLocked(devPath, name, state); 3812f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } 3822f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } catch (NumberFormatException e) { 3832f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner Slog.e(TAG, "Could not parse switch state from event " + event); 3842f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } 3852f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } 3862f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 3872f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner private void updateStateLocked(String devPath, String name, int state) { 3882f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner for (int i = 0; i < mUEventInfo.size(); ++i) { 3892f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner UEventInfo uei = mUEventInfo.get(i); 3902f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner if (devPath.equals(uei.getDevPath())) { 3912f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner updateLocked(name, uei.computeNewHeadsetState(mHeadsetState, state)); 3922f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner return; 3932f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } 3942f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } 3952f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } 3962f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 3972f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner private final class UEventInfo { 3982f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner private final String mDevName; 3992f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner private final int mState1Bits; 4002f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner private final int mState2Bits; 4012f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 4022f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner public UEventInfo(String devName, int state1Bits, int state2Bits) { 4032f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner mDevName = devName; 4042f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner mState1Bits = state1Bits; 4052f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner mState2Bits = state2Bits; 4062f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } 4072f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 4082f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner public String getDevName() { return mDevName; } 4092f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 4102f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner public String getDevPath() { 4112f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner return String.format("/devices/virtual/switch/%s", mDevName); 4122f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } 4132f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 4142f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner public String getSwitchStatePath() { 4152f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner return String.format("/sys/class/switch/%s/state", mDevName); 4162f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } 4172f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 4182f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner public boolean checkSwitchExists() { 4192f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner File f = new File(getSwitchStatePath()); 4202f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner return f.exists(); 4212f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } 4222f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 4232f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner public int computeNewHeadsetState(int headsetState, int switchState) { 4242f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner int preserveMask = ~(mState1Bits | mState2Bits); 4252f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner int setBits = ((switchState == 1) ? mState1Bits : 4262f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner ((switchState == 2) ? mState2Bits : 0)); 4272f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner 4282f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner return ((headsetState & preserveMask) | setBits); 4292f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } 4302f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } 4312f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner } 4322f39e9f8333183312b7f7d423c2ea60a93a25e32Craig Mautner} 433