blob: 120d1ce38f9f964d49f6a1eef2b652059656f5e6 [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() {
David Lin22c2ce92017-07-28 12:01:24 -070063 final boolean isPluggedIn = isWiredHeadsetPluggedIn();
Hall Liuca9988b2016-03-08 15:43:45 -080064
Hall Liu31ed9be2016-04-06 12:07:31 -070065 Log.i(WiredHeadsetManager.this, "ACTION_HEADSET_PLUG event, plugged in: %b, ",
66 isPluggedIn);
Hall Liuca9988b2016-03-08 15:43:45 -080067 onHeadsetPluggedInChanged(isPluggedIn);
68 }
Sailesh Nepal6aca10a2014-03-24 16:11:02 -070069 }
70
Santos Cordonc395e492015-09-25 14:06:54 -070071 private final AudioManager mAudioManager;
Sailesh Nepal6aca10a2014-03-24 16:11:02 -070072 private boolean mIsPluggedIn;
Jay Shraunera82c8f72014-08-14 15:49:16 -070073 /**
74 * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is
75 * load factor before resizing, 1 means we only expect a single thread to
76 * access the map so make only a single shard
77 */
78 private final Set<Listener> mListeners = Collections.newSetFromMap(
Hall Liuca9988b2016-03-08 15:43:45 -080079 new ConcurrentHashMap<>(8, 0.9f, 1));
Sailesh Nepal6aca10a2014-03-24 16:11:02 -070080
Hall Liuf62630a2015-10-27 14:53:39 -070081 public WiredHeadsetManager(Context context) {
Santos Cordonc395e492015-09-25 14:06:54 -070082 mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
David Lin22c2ce92017-07-28 12:01:24 -070083 mIsPluggedIn = isWiredHeadsetPluggedIn();
Sailesh Nepal6aca10a2014-03-24 16:11:02 -070084
Hall Liuca9988b2016-03-08 15:43:45 -080085 mAudioManager.registerAudioDeviceCallback(new WiredHeadsetCallback(), null);
Sailesh Nepal6aca10a2014-03-24 16:11:02 -070086 }
87
Hall Liuf62630a2015-10-27 14:53:39 -070088 @VisibleForTesting
89 public void addListener(Listener listener) {
Sailesh Nepalb88795a2014-07-15 14:53:27 -070090 mListeners.add(listener);
91 }
92
93 void removeListener(Listener listener) {
Jay Shraunera82c8f72014-08-14 15:49:16 -070094 if (listener != null) {
95 mListeners.remove(listener);
96 }
Sailesh Nepalb88795a2014-07-15 14:53:27 -070097 }
98
Hall Liuf62630a2015-10-27 14:53:39 -070099 @VisibleForTesting
100 public boolean isPluggedIn() {
Sailesh Nepal6aca10a2014-03-24 16:11:02 -0700101 return mIsPluggedIn;
102 }
103
David Lin22c2ce92017-07-28 12:01:24 -0700104 private boolean isWiredHeadsetPluggedIn() {
105 AudioDeviceInfo[] devices = mAudioManager.getDevices(AudioManager.GET_DEVICES_ALL);
106 boolean isPluggedIn = false;
107 for (AudioDeviceInfo device : devices) {
108 switch (device.getType()) {
109 case AudioDeviceInfo.TYPE_WIRED_HEADPHONES:
110 case AudioDeviceInfo.TYPE_WIRED_HEADSET:
111 case AudioDeviceInfo.TYPE_USB_HEADSET:
112 case AudioDeviceInfo.TYPE_USB_DEVICE:
113 isPluggedIn = true;
114 }
115 if (isPluggedIn) {
116 break;
117 }
118 }
119 return isPluggedIn;
120 }
121
Sailesh Nepal6aca10a2014-03-24 16:11:02 -0700122 private void onHeadsetPluggedInChanged(boolean isPluggedIn) {
123 if (mIsPluggedIn != isPluggedIn) {
124 Log.v(this, "onHeadsetPluggedInChanged, mIsPluggedIn: %b -> %b", mIsPluggedIn,
125 isPluggedIn);
126 boolean oldIsPluggedIn = mIsPluggedIn;
127 mIsPluggedIn = isPluggedIn;
Sailesh Nepalb88795a2014-07-15 14:53:27 -0700128 for (Listener listener : mListeners) {
129 listener.onWiredHeadsetPluggedInChanged(oldIsPluggedIn, mIsPluggedIn);
130 }
Sailesh Nepal6aca10a2014-03-24 16:11:02 -0700131 }
132 }
Tyler Gunn9787e0e2014-10-14 14:36:12 -0700133
134 /**
135 * Dumps the state of the {@link WiredHeadsetManager}.
136 *
137 * @param pw The {@code IndentingPrintWriter} to write the state to.
138 */
139 public void dump(IndentingPrintWriter pw) {
140 pw.println("mIsPluggedIn: " + mIsPluggedIn);
141 }
Sailesh Nepal6aca10a2014-03-24 16:11:02 -0700142}