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