blob: a5e440438b0c4a723ea20cfbc6252aa5ed297c6e [file] [log] [blame]
Sailesh Nepal6aca10a2014-03-24 16:11:02 -07001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Tyler Gunn7cc70b42014-09-12 22:17:27 -070017package com.android.server.telecom;
Sailesh Nepal6aca10a2014-03-24 16:11:02 -070018
Sailesh Nepal6aca10a2014-03-24 16:11:02 -070019import android.content.Context;
Hall Liuca9988b2016-03-08 15:43:45 -080020import android.media.AudioDeviceCallback;
21import android.media.AudioDeviceInfo;
Sailesh Nepal6aca10a2014-03-24 16:11:02 -070022import android.media.AudioManager;
Brad Ebingera3eccfe2016-10-05 15:45:22 -070023import android.telecom.Log;
Sailesh Nepal6aca10a2014-03-24 16:11:02 -070024
Hall Liuf62630a2015-10-27 14:53:39 -070025import com.android.internal.annotations.VisibleForTesting;
Tyler Gunn9787e0e2014-10-14 14:36:12 -070026import com.android.internal.util.IndentingPrintWriter;
27
Jay Shraunera82c8f72014-08-14 15:49:16 -070028import java.util.Collections;
29import java.util.Set;
30import java.util.concurrent.ConcurrentHashMap;
Sailesh Nepalb88795a2014-07-15 14:53:27 -070031
32/** Listens for and caches headset state. */
Hall Liuf62630a2015-10-27 14:53:39 -070033@VisibleForTesting
34public class WiredHeadsetManager {
35 @VisibleForTesting
36 public interface Listener {
Sailesh Nepalb88795a2014-07-15 14:53:27 -070037 void onWiredHeadsetPluggedInChanged(boolean oldIsPluggedIn, boolean newIsPluggedIn);
38 }
39
Sailesh Nepal6aca10a2014-03-24 16:11:02 -070040 /** Receiver for wired headset plugged and unplugged events. */
Hall Liuca9988b2016-03-08 15:43:45 -080041 private class WiredHeadsetCallback extends AudioDeviceCallback {
Sailesh Nepal6aca10a2014-03-24 16:11:02 -070042 @Override
Hall Liuca9988b2016-03-08 15:43:45 -080043 public void onAudioDevicesAdded(AudioDeviceInfo[] addedDevices) {
44 Log.startSession("WHC.oADA");
Brad Ebinger58f36582016-01-21 14:20:07 -080045 try {
Hall Liuca9988b2016-03-08 15:43:45 -080046 updateHeadsetStatus();
Brad Ebinger58f36582016-01-21 14:20:07 -080047 } finally {
48 Log.endSession();
Sailesh Nepal6aca10a2014-03-24 16:11:02 -070049 }
50 }
Hall Liuca9988b2016-03-08 15:43:45 -080051
52 @Override
53 public void onAudioDevicesRemoved(AudioDeviceInfo[] devices) {
54 Log.startSession("WHC.oADR");
55 try {
56 updateHeadsetStatus();
57 } finally {
58 Log.endSession();
59 }
60 }
61
62 private void updateHeadsetStatus() {
Hall Liu31ed9be2016-04-06 12:07:31 -070063 AudioDeviceInfo[] devices = mAudioManager.getDevices(AudioManager.GET_DEVICES_ALL);
64 boolean isPluggedIn = false;
65 for (AudioDeviceInfo device : devices) {
66 switch (device.getType()) {
67 case AudioDeviceInfo.TYPE_WIRED_HEADPHONES:
68 case AudioDeviceInfo.TYPE_WIRED_HEADSET:
69 case AudioDeviceInfo.TYPE_USB_DEVICE:
70 isPluggedIn = true;
71 }
72 }
Hall Liuca9988b2016-03-08 15:43:45 -080073
Hall Liu31ed9be2016-04-06 12:07:31 -070074 Log.i(WiredHeadsetManager.this, "ACTION_HEADSET_PLUG event, plugged in: %b, ",
75 isPluggedIn);
Hall Liuca9988b2016-03-08 15:43:45 -080076 onHeadsetPluggedInChanged(isPluggedIn);
77 }
Sailesh Nepal6aca10a2014-03-24 16:11:02 -070078 }
79
Santos Cordonc395e492015-09-25 14:06:54 -070080 private final AudioManager mAudioManager;
Sailesh Nepal6aca10a2014-03-24 16:11:02 -070081 private boolean mIsPluggedIn;
Jay Shraunera82c8f72014-08-14 15:49:16 -070082 /**
83 * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is
84 * load factor before resizing, 1 means we only expect a single thread to
85 * access the map so make only a single shard
86 */
87 private final Set<Listener> mListeners = Collections.newSetFromMap(
Hall Liuca9988b2016-03-08 15:43:45 -080088 new ConcurrentHashMap<>(8, 0.9f, 1));
Sailesh Nepal6aca10a2014-03-24 16:11:02 -070089
Hall Liuf62630a2015-10-27 14:53:39 -070090 public WiredHeadsetManager(Context context) {
Santos Cordonc395e492015-09-25 14:06:54 -070091 mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
92 mIsPluggedIn = mAudioManager.isWiredHeadsetOn();
Sailesh Nepal6aca10a2014-03-24 16:11:02 -070093
Hall Liuca9988b2016-03-08 15:43:45 -080094 mAudioManager.registerAudioDeviceCallback(new WiredHeadsetCallback(), null);
Sailesh Nepal6aca10a2014-03-24 16:11:02 -070095 }
96
Hall Liuf62630a2015-10-27 14:53:39 -070097 @VisibleForTesting
98 public void addListener(Listener listener) {
Sailesh Nepalb88795a2014-07-15 14:53:27 -070099 mListeners.add(listener);
100 }
101
102 void removeListener(Listener listener) {
Jay Shraunera82c8f72014-08-14 15:49:16 -0700103 if (listener != null) {
104 mListeners.remove(listener);
105 }
Sailesh Nepalb88795a2014-07-15 14:53:27 -0700106 }
107
Hall Liuf62630a2015-10-27 14:53:39 -0700108 @VisibleForTesting
109 public boolean isPluggedIn() {
Sailesh Nepal6aca10a2014-03-24 16:11:02 -0700110 return mIsPluggedIn;
111 }
112
113 private void onHeadsetPluggedInChanged(boolean isPluggedIn) {
114 if (mIsPluggedIn != isPluggedIn) {
115 Log.v(this, "onHeadsetPluggedInChanged, mIsPluggedIn: %b -> %b", mIsPluggedIn,
116 isPluggedIn);
117 boolean oldIsPluggedIn = mIsPluggedIn;
118 mIsPluggedIn = isPluggedIn;
Sailesh Nepalb88795a2014-07-15 14:53:27 -0700119 for (Listener listener : mListeners) {
120 listener.onWiredHeadsetPluggedInChanged(oldIsPluggedIn, mIsPluggedIn);
121 }
Sailesh Nepal6aca10a2014-03-24 16:11:02 -0700122 }
123 }
Tyler Gunn9787e0e2014-10-14 14:36:12 -0700124
125 /**
126 * Dumps the state of the {@link WiredHeadsetManager}.
127 *
128 * @param pw The {@code IndentingPrintWriter} to write the state to.
129 */
130 public void dump(IndentingPrintWriter pw) {
131 pw.println("mIsPluggedIn: " + mIsPluggedIn);
132 }
Sailesh Nepal6aca10a2014-03-24 16:11:02 -0700133}