WiredHeadsetManager.java revision c395e49e7b9aef59e5b4092945a8648f5adba3a0
16aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal/*
26aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal * Copyright (C) 2014 The Android Open Source Project
36aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal *
46aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal * Licensed under the Apache License, Version 2.0 (the "License");
56aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal * you may not use this file except in compliance with the License.
66aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal * You may obtain a copy of the License at
76aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal *
86aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal *      http://www.apache.org/licenses/LICENSE-2.0
96aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal *
106aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal * Unless required by applicable law or agreed to in writing, software
116aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal * distributed under the License is distributed on an "AS IS" BASIS,
126aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal * See the License for the specific language governing permissions and
146aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal * limitations under the License.
156aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal */
166aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal
177cc70b4f0ad1064a4a0dce6056ad82b205887160Tyler Gunnpackage com.android.server.telecom;
186aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal
196aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepalimport android.content.BroadcastReceiver;
206aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepalimport android.content.Context;
216aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepalimport android.content.Intent;
226aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepalimport android.content.IntentFilter;
236aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepalimport android.media.AudioManager;
246aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal
259787e0e80d8960cf8b0ca74c7cdc4c4aac97187aTyler Gunnimport com.android.internal.util.IndentingPrintWriter;
269787e0e80d8960cf8b0ca74c7cdc4c4aac97187aTyler Gunn
27a82c8f794a0a1a9eaa1329a6361abe28043d139aJay Shraunerimport java.util.Collections;
28a82c8f794a0a1a9eaa1329a6361abe28043d139aJay Shraunerimport java.util.Set;
29a82c8f794a0a1a9eaa1329a6361abe28043d139aJay Shraunerimport java.util.concurrent.ConcurrentHashMap;
30b88795aadc636d14156791c2fc93af051d7e0d49Sailesh Nepal
31b88795aadc636d14156791c2fc93af051d7e0d49Sailesh Nepal/** Listens for and caches headset state. */
326aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepalclass WiredHeadsetManager {
33b88795aadc636d14156791c2fc93af051d7e0d49Sailesh Nepal    interface Listener {
34b88795aadc636d14156791c2fc93af051d7e0d49Sailesh Nepal        void onWiredHeadsetPluggedInChanged(boolean oldIsPluggedIn, boolean newIsPluggedIn);
35b88795aadc636d14156791c2fc93af051d7e0d49Sailesh Nepal    }
36b88795aadc636d14156791c2fc93af051d7e0d49Sailesh Nepal
376aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal    /** Receiver for wired headset plugged and unplugged events. */
386aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal    private class WiredHeadsetBroadcastReceiver extends BroadcastReceiver {
396aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal        @Override
406aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal        public void onReceive(Context context, Intent intent) {
416aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal            if (intent.getAction().equals(Intent.ACTION_HEADSET_PLUG)) {
42c395e49e7b9aef59e5b4092945a8648f5adba3a0Santos Cordon                boolean isPluggedIn = mAudioManager.isWiredHeadsetOn();
436aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal                Log.v(WiredHeadsetManager.this, "ACTION_HEADSET_PLUG event, plugged in: %b",
446aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal                        isPluggedIn);
456aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal                onHeadsetPluggedInChanged(isPluggedIn);
466aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal            }
476aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal        }
486aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal    }
496aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal
506aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal    private final WiredHeadsetBroadcastReceiver mReceiver;
51c395e49e7b9aef59e5b4092945a8648f5adba3a0Santos Cordon    private final AudioManager mAudioManager;
526aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal    private boolean mIsPluggedIn;
53a82c8f794a0a1a9eaa1329a6361abe28043d139aJay Shrauner    /**
54a82c8f794a0a1a9eaa1329a6361abe28043d139aJay Shrauner     * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is
55a82c8f794a0a1a9eaa1329a6361abe28043d139aJay Shrauner     * load factor before resizing, 1 means we only expect a single thread to
56a82c8f794a0a1a9eaa1329a6361abe28043d139aJay Shrauner     * access the map so make only a single shard
57a82c8f794a0a1a9eaa1329a6361abe28043d139aJay Shrauner     */
58a82c8f794a0a1a9eaa1329a6361abe28043d139aJay Shrauner    private final Set<Listener> mListeners = Collections.newSetFromMap(
59a82c8f794a0a1a9eaa1329a6361abe28043d139aJay Shrauner            new ConcurrentHashMap<Listener, Boolean>(8, 0.9f, 1));
606aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal
61b88795aadc636d14156791c2fc93af051d7e0d49Sailesh Nepal    WiredHeadsetManager(Context context) {
626aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal        mReceiver = new WiredHeadsetBroadcastReceiver();
636aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal
64c395e49e7b9aef59e5b4092945a8648f5adba3a0Santos Cordon        mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
65c395e49e7b9aef59e5b4092945a8648f5adba3a0Santos Cordon        mIsPluggedIn = mAudioManager.isWiredHeadsetOn();
666aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal
676aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal        // Register for misc other intent broadcasts.
686aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal        IntentFilter intentFilter = new IntentFilter(Intent.ACTION_HEADSET_PLUG);
696aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal        context.registerReceiver(mReceiver, intentFilter);
706aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal    }
716aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal
72b88795aadc636d14156791c2fc93af051d7e0d49Sailesh Nepal    void addListener(Listener listener) {
73b88795aadc636d14156791c2fc93af051d7e0d49Sailesh Nepal        mListeners.add(listener);
74b88795aadc636d14156791c2fc93af051d7e0d49Sailesh Nepal    }
75b88795aadc636d14156791c2fc93af051d7e0d49Sailesh Nepal
76b88795aadc636d14156791c2fc93af051d7e0d49Sailesh Nepal    void removeListener(Listener listener) {
77a82c8f794a0a1a9eaa1329a6361abe28043d139aJay Shrauner        if (listener != null) {
78a82c8f794a0a1a9eaa1329a6361abe28043d139aJay Shrauner            mListeners.remove(listener);
79a82c8f794a0a1a9eaa1329a6361abe28043d139aJay Shrauner        }
80b88795aadc636d14156791c2fc93af051d7e0d49Sailesh Nepal    }
81b88795aadc636d14156791c2fc93af051d7e0d49Sailesh Nepal
826aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal    boolean isPluggedIn() {
836aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal        return mIsPluggedIn;
846aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal    }
856aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal
866aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal    private void onHeadsetPluggedInChanged(boolean isPluggedIn) {
876aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal        if (mIsPluggedIn != isPluggedIn) {
886aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal            Log.v(this, "onHeadsetPluggedInChanged, mIsPluggedIn: %b -> %b", mIsPluggedIn,
896aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal                    isPluggedIn);
906aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal            boolean oldIsPluggedIn = mIsPluggedIn;
916aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal            mIsPluggedIn = isPluggedIn;
92b88795aadc636d14156791c2fc93af051d7e0d49Sailesh Nepal            for (Listener listener : mListeners) {
93b88795aadc636d14156791c2fc93af051d7e0d49Sailesh Nepal                listener.onWiredHeadsetPluggedInChanged(oldIsPluggedIn, mIsPluggedIn);
94b88795aadc636d14156791c2fc93af051d7e0d49Sailesh Nepal            }
956aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal        }
966aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal    }
979787e0e80d8960cf8b0ca74c7cdc4c4aac97187aTyler Gunn
989787e0e80d8960cf8b0ca74c7cdc4c4aac97187aTyler Gunn    /**
999787e0e80d8960cf8b0ca74c7cdc4c4aac97187aTyler Gunn     * Dumps the state of the {@link WiredHeadsetManager}.
1009787e0e80d8960cf8b0ca74c7cdc4c4aac97187aTyler Gunn     *
1019787e0e80d8960cf8b0ca74c7cdc4c4aac97187aTyler Gunn     * @param pw The {@code IndentingPrintWriter} to write the state to.
1029787e0e80d8960cf8b0ca74c7cdc4c4aac97187aTyler Gunn     */
1039787e0e80d8960cf8b0ca74c7cdc4c4aac97187aTyler Gunn    public void dump(IndentingPrintWriter pw) {
1049787e0e80d8960cf8b0ca74c7cdc4c4aac97187aTyler Gunn        pw.println("mIsPluggedIn: " + mIsPluggedIn);
1059787e0e80d8960cf8b0ca74c7cdc4c4aac97187aTyler Gunn    }
1066aca10a0efa2771ccdef5920f4276f0db4a7ee1fSailesh Nepal}
107