blob: 1c7db78f0fa04eaba2bf3d5b1afbb6ec00050cff [file] [log] [blame]
Hall Liuf62630a2015-10-27 14:53:39 -07001/*
2 * Copyright (C) 2015 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
17package com.android.server.telecom;
18
19
Sudheer Shanka873dc732016-11-10 16:37:28 -080020import android.app.ActivityManager;
Hall Liu132a5572017-11-02 18:44:57 -070021import android.bluetooth.BluetoothDevice;
22import android.bluetooth.BluetoothHeadset;
Hall Liuf62630a2015-10-27 14:53:39 -070023import android.content.Context;
24import android.content.pm.UserInfo;
Scott Randolph8aba9d62017-11-01 18:34:19 -070025import android.media.AudioDeviceInfo;
Hall Liuf62630a2015-10-27 14:53:39 -070026import android.media.AudioManager;
27import android.media.IAudioService;
28import android.os.Binder;
29import android.os.Message;
30import android.os.RemoteException;
Hall Liua3e9dda2015-12-15 17:52:50 -080031import android.os.SystemProperties;
Hall Liuf62630a2015-10-27 14:53:39 -070032import android.os.UserHandle;
33import android.telecom.CallAudioState;
Brad Ebingera3eccfe2016-10-05 15:45:22 -070034import android.telecom.Log;
35import android.telecom.Logging.Session;
Hall Liuef15aea2016-01-05 16:25:51 -080036import android.util.SparseArray;
Hall Liuf62630a2015-10-27 14:53:39 -070037
Hall Liu37f18d52017-08-18 14:20:26 -070038import com.android.internal.annotations.VisibleForTesting;
Hall Liu9086fb12017-11-07 18:01:53 -080039import com.android.internal.os.SomeArgs;
Hall Liuf62630a2015-10-27 14:53:39 -070040import com.android.internal.util.IState;
Hall Liua51c99f2017-03-13 16:39:26 -070041import com.android.internal.util.IndentingPrintWriter;
Hall Liuf62630a2015-10-27 14:53:39 -070042import com.android.internal.util.State;
43import com.android.internal.util.StateMachine;
Hall Liu486cb192016-10-21 18:23:33 -070044import com.android.server.telecom.bluetooth.BluetoothRouteManager;
Hall Liuf62630a2015-10-27 14:53:39 -070045
Hall Liu132a5572017-11-02 18:44:57 -070046import java.util.Collection;
Hall Liuf62630a2015-10-27 14:53:39 -070047import java.util.HashMap;
Hall Liu9086fb12017-11-07 18:01:53 -080048import java.util.Objects;
Hall Liuf62630a2015-10-27 14:53:39 -070049
50/**
51 * This class describes the available routes of a call as a state machine.
52 * Transitions are caused solely by the commands sent as messages. Possible values for msg.what
53 * are defined as event constants in this file.
54 *
55 * The eight states are all instances of the abstract base class, {@link AudioState}. Each state
56 * is a combination of one of the four audio routes (earpiece, wired headset, bluetooth, and
57 * speakerphone) and audio focus status (active or quiescent).
58 *
59 * Messages are processed first by the processMessage method in the base class, AudioState.
60 * Any messages not completely handled by AudioState are further processed by the same method in
61 * the route-specific abstract classes: {@link EarpieceRoute}, {@link HeadsetRoute},
62 * {@link BluetoothRoute}, and {@link SpeakerRoute}. Finally, messages that are not handled at
63 * this level are then processed by the classes corresponding to the state instances themselves.
64 *
65 * There are several variables carrying additional state. These include:
66 * mAvailableRoutes: A bitmask describing which audio routes are available
67 * mWasOnSpeaker: A boolean indicating whether we should switch to speakerphone after disconnecting
68 * from a wired headset
69 * mIsMuted: a boolean indicating whether the audio is muted
70 */
71public class CallAudioRouteStateMachine extends StateMachine {
Scott Randolph8aba9d62017-11-01 18:34:19 -070072
73 /** Values for CallAudioRouteStateMachine constructor's earPieceRouting arg. */
74 public static final int EARPIECE_FORCE_DISABLED = 0;
75 public static final int EARPIECE_FORCE_ENABLED = 1;
76 public static final int EARPIECE_AUTO_DETECT = 2;
77
Hall Liuf62630a2015-10-27 14:53:39 -070078 /** Direct the audio stream through the device's earpiece. */
79 public static final int ROUTE_EARPIECE = CallAudioState.ROUTE_EARPIECE;
80
81 /** Direct the audio stream through Bluetooth. */
82 public static final int ROUTE_BLUETOOTH = CallAudioState.ROUTE_BLUETOOTH;
83
84 /** Direct the audio stream through a wired headset. */
85 public static final int ROUTE_WIRED_HEADSET = CallAudioState.ROUTE_WIRED_HEADSET;
86
87 /** Direct the audio stream through the device's speakerphone. */
88 public static final int ROUTE_SPEAKER = CallAudioState.ROUTE_SPEAKER;
89
90 /** Valid values for msg.what */
91 public static final int CONNECT_WIRED_HEADSET = 1;
92 public static final int DISCONNECT_WIRED_HEADSET = 2;
93 public static final int CONNECT_BLUETOOTH = 3;
94 public static final int DISCONNECT_BLUETOOTH = 4;
95 public static final int CONNECT_DOCK = 5;
96 public static final int DISCONNECT_DOCK = 6;
Hall Liu132a5572017-11-02 18:44:57 -070097 public static final int BLUETOOTH_DEVICE_LIST_CHANGED = 7;
Hall Liuf62630a2015-10-27 14:53:39 -070098
99 public static final int SWITCH_EARPIECE = 1001;
100 public static final int SWITCH_BLUETOOTH = 1002;
101 public static final int SWITCH_HEADSET = 1003;
102 public static final int SWITCH_SPEAKER = 1004;
Hall Liua3e9dda2015-12-15 17:52:50 -0800103 // Wired headset, earpiece, or speakerphone, in that order of precedence.
104 public static final int SWITCH_BASELINE_ROUTE = 1005;
Hall Liuf62630a2015-10-27 14:53:39 -0700105
Hall Liu4f296ba2016-02-18 14:46:57 -0800106 public static final int USER_SWITCH_EARPIECE = 1101;
107 public static final int USER_SWITCH_BLUETOOTH = 1102;
108 public static final int USER_SWITCH_HEADSET = 1103;
109 public static final int USER_SWITCH_SPEAKER = 1104;
110 public static final int USER_SWITCH_BASELINE_ROUTE = 1105;
111
Hall Liu8c7e2562016-04-13 18:26:03 -0700112 public static final int UPDATE_SYSTEM_AUDIO_ROUTE = 1201;
113
Hall Liu132a5572017-11-02 18:44:57 -0700114 // These three messages indicate state changes that come from BluetoothRouteManager.
115 // They may be triggered by the BT stack doing something on its own or they may be sent after
116 // we request that the BT stack do something. Any logic for these messages should take into
117 // account the possibility that the event indicated has already been processed (i.e. handling
118 // should be idempotent).
119 public static final int BT_AUDIO_DISCONNECTED = 1301;
120 public static final int BT_AUDIO_CONNECTED = 1302;
121 public static final int BT_AUDIO_PENDING = 1303;
122
Hall Liuf62630a2015-10-27 14:53:39 -0700123 public static final int MUTE_ON = 3001;
124 public static final int MUTE_OFF = 3002;
125 public static final int TOGGLE_MUTE = 3003;
126
127 public static final int SWITCH_FOCUS = 4001;
128
Hall Liu29855702015-12-11 17:42:03 -0800129 // Used in testing to execute verifications. Not compatible with subsessions.
130 public static final int RUN_RUNNABLE = 9001;
131
Hall Liuf62630a2015-10-27 14:53:39 -0700132 /** Valid values for mAudioFocusType */
133 public static final int NO_FOCUS = 1;
Hall Liue271f222016-08-15 18:04:06 -0700134 public static final int ACTIVE_FOCUS = 2;
135 public static final int RINGING_FOCUS = 3;
Hall Liuf62630a2015-10-27 14:53:39 -0700136
Hall Liu95f2db92017-06-19 18:32:55 -0700137 /** Valid values for the argument for SWITCH_BASELINE_ROUTE */
138 public static final int NO_INCLUDE_BLUETOOTH_IN_BASELINE = 0;
139 public static final int INCLUDE_BLUETOOTH_IN_BASELINE = 1;
140
Hall Liu37f18d52017-08-18 14:20:26 -0700141 @VisibleForTesting
142 public static final SparseArray<String> AUDIO_ROUTE_TO_LOG_EVENT = new SparseArray<String>() {{
Brad Ebingera3eccfe2016-10-05 15:45:22 -0700143 put(CallAudioState.ROUTE_BLUETOOTH, LogUtils.Events.AUDIO_ROUTE_BT);
144 put(CallAudioState.ROUTE_EARPIECE, LogUtils.Events.AUDIO_ROUTE_EARPIECE);
145 put(CallAudioState.ROUTE_SPEAKER, LogUtils.Events.AUDIO_ROUTE_SPEAKER);
146 put(CallAudioState.ROUTE_WIRED_HEADSET, LogUtils.Events.AUDIO_ROUTE_HEADSET);
Hall Liu874c0f82016-04-29 18:13:18 -0700147 }};
148
Hall Liuef15aea2016-01-05 16:25:51 -0800149 private static final SparseArray<String> MESSAGE_CODE_TO_NAME = new SparseArray<String>() {{
150 put(CONNECT_WIRED_HEADSET, "CONNECT_WIRED_HEADSET");
151 put(DISCONNECT_WIRED_HEADSET, "DISCONNECT_WIRED_HEADSET");
152 put(CONNECT_BLUETOOTH, "CONNECT_BLUETOOTH");
153 put(DISCONNECT_BLUETOOTH, "DISCONNECT_BLUETOOTH");
154 put(CONNECT_DOCK, "CONNECT_DOCK");
155 put(DISCONNECT_DOCK, "DISCONNECT_DOCK");
Hall Liu132a5572017-11-02 18:44:57 -0700156 put(BLUETOOTH_DEVICE_LIST_CHANGED, "BLUETOOTH_DEVICE_LIST_CHANGED");
Hall Liuef15aea2016-01-05 16:25:51 -0800157
158 put(SWITCH_EARPIECE, "SWITCH_EARPIECE");
159 put(SWITCH_BLUETOOTH, "SWITCH_BLUETOOTH");
160 put(SWITCH_HEADSET, "SWITCH_HEADSET");
161 put(SWITCH_SPEAKER, "SWITCH_SPEAKER");
Hall Liua3e9dda2015-12-15 17:52:50 -0800162 put(SWITCH_BASELINE_ROUTE, "SWITCH_BASELINE_ROUTE");
Hall Liuef15aea2016-01-05 16:25:51 -0800163
Hall Liu4f296ba2016-02-18 14:46:57 -0800164 put(USER_SWITCH_EARPIECE, "USER_SWITCH_EARPIECE");
165 put(USER_SWITCH_BLUETOOTH, "USER_SWITCH_BLUETOOTH");
166 put(USER_SWITCH_HEADSET, "USER_SWITCH_HEADSET");
167 put(USER_SWITCH_SPEAKER, "USER_SWITCH_SPEAKER");
168 put(USER_SWITCH_BASELINE_ROUTE, "USER_SWITCH_BASELINE_ROUTE");
169
Hall Liue271f222016-08-15 18:04:06 -0700170 put(UPDATE_SYSTEM_AUDIO_ROUTE, "UPDATE_SYSTEM_AUDIO_ROUTE");
171
Hall Liu132a5572017-11-02 18:44:57 -0700172 put(BT_AUDIO_DISCONNECTED, "BT_AUDIO_DISCONNECTED");
173 put(BT_AUDIO_CONNECTED, "BT_AUDIO_CONNECTED");
174 put(BT_AUDIO_PENDING, "BT_AUDIO_PENDING");
175
Hall Liuef15aea2016-01-05 16:25:51 -0800176 put(MUTE_ON, "MUTE_ON");
177 put(MUTE_OFF, "MUTE_OFF");
178 put(TOGGLE_MUTE, "TOGGLE_MUTE");
179
180 put(SWITCH_FOCUS, "SWITCH_FOCUS");
181
182 put(RUN_RUNNABLE, "RUN_RUNNABLE");
183 }};
184
Hall Liuf62630a2015-10-27 14:53:39 -0700185 private static final String ACTIVE_EARPIECE_ROUTE_NAME = "ActiveEarpieceRoute";
186 private static final String ACTIVE_BLUETOOTH_ROUTE_NAME = "ActiveBluetoothRoute";
187 private static final String ACTIVE_SPEAKER_ROUTE_NAME = "ActiveSpeakerRoute";
188 private static final String ACTIVE_HEADSET_ROUTE_NAME = "ActiveHeadsetRoute";
Hall Liue271f222016-08-15 18:04:06 -0700189 private static final String RINGING_BLUETOOTH_ROUTE_NAME = "RingingBluetoothRoute";
Hall Liuf62630a2015-10-27 14:53:39 -0700190 private static final String QUIESCENT_EARPIECE_ROUTE_NAME = "QuiescentEarpieceRoute";
191 private static final String QUIESCENT_BLUETOOTH_ROUTE_NAME = "QuiescentBluetoothRoute";
192 private static final String QUIESCENT_SPEAKER_ROUTE_NAME = "QuiescentSpeakerRoute";
193 private static final String QUIESCENT_HEADSET_ROUTE_NAME = "QuiescentHeadsetRoute";
194
195 public static final String NAME = CallAudioRouteStateMachine.class.getName();
196
Brad Ebinger11623a32015-11-25 13:52:02 -0800197 @Override
198 protected void onPreHandleMessage(Message msg) {
Hall Liu9086fb12017-11-07 18:01:53 -0800199 if (msg.obj != null && msg.obj instanceof SomeArgs) {
200 Session session = (Session) ((SomeArgs) msg.obj).arg1;
Hall Liuef15aea2016-01-05 16:25:51 -0800201 String messageCodeName = MESSAGE_CODE_TO_NAME.get(msg.what, "unknown");
Hall Liu9086fb12017-11-07 18:01:53 -0800202 Log.continueSession(session, "CARSM.pM_" + messageCodeName);
Hall Liue271f222016-08-15 18:04:06 -0700203 Log.i(this, "Message received: %s=%d, arg1=%d", messageCodeName, msg.what, msg.arg1);
Brad Ebinger11623a32015-11-25 13:52:02 -0800204 }
205 }
206
207 @Override
208 protected void onPostHandleMessage(Message msg) {
209 Log.endSession();
Hall Liu9086fb12017-11-07 18:01:53 -0800210 if (msg.obj != null && msg.obj instanceof SomeArgs) {
211 ((SomeArgs) msg.obj).recycle();
212 }
Brad Ebinger11623a32015-11-25 13:52:02 -0800213 }
214
Hall Liuf62630a2015-10-27 14:53:39 -0700215 abstract class AudioState extends State {
216 @Override
217 public void enter() {
218 super.enter();
Brad Ebingera3eccfe2016-10-05 15:45:22 -0700219 Log.addEvent(mCallsManager.getForegroundCall(), LogUtils.Events.AUDIO_ROUTE,
Hall Liuf62630a2015-10-27 14:53:39 -0700220 "Entering state " + getName());
Hall Liu37f18d52017-08-18 14:20:26 -0700221 if (isActive()) {
222 Log.addEvent(mCallsManager.getForegroundCall(),
Tyler Gunne04538f2017-11-17 15:18:47 -0800223 AUDIO_ROUTE_TO_LOG_EVENT.get(getRouteCode(), LogUtils.Events.AUDIO_ROUTE),
224 getVolumeString()
225 );
Hall Liu37f18d52017-08-18 14:20:26 -0700226 }
Hall Liuf62630a2015-10-27 14:53:39 -0700227 }
228
229 @Override
230 public void exit() {
Brad Ebingera3eccfe2016-10-05 15:45:22 -0700231 Log.addEvent(mCallsManager.getForegroundCall(), LogUtils.Events.AUDIO_ROUTE,
Hall Liuf62630a2015-10-27 14:53:39 -0700232 "Leaving state " + getName());
233 super.exit();
234 }
235
236 @Override
237 public boolean processMessage(Message msg) {
Christine Hallstrom96a0be62016-11-30 16:05:13 -0800238 int addedRoutes = 0;
239 int removedRoutes = 0;
Hall Liu132a5572017-11-02 18:44:57 -0700240 boolean isHandled = NOT_HANDLED;
Christine Hallstrom96a0be62016-11-30 16:05:13 -0800241
Hall Liuf62630a2015-10-27 14:53:39 -0700242 switch (msg.what) {
243 case CONNECT_WIRED_HEADSET:
Brad Ebingera3eccfe2016-10-05 15:45:22 -0700244 Log.addEvent(mCallsManager.getForegroundCall(), LogUtils.Events.AUDIO_ROUTE,
Hall Liuf62630a2015-10-27 14:53:39 -0700245 "Wired headset connected");
Christine Hallstrom96a0be62016-11-30 16:05:13 -0800246 removedRoutes |= ROUTE_EARPIECE;
247 addedRoutes |= ROUTE_WIRED_HEADSET;
248 break;
Hall Liuf62630a2015-10-27 14:53:39 -0700249 case CONNECT_BLUETOOTH:
Brad Ebingera3eccfe2016-10-05 15:45:22 -0700250 Log.addEvent(mCallsManager.getForegroundCall(), LogUtils.Events.AUDIO_ROUTE,
Hall Liue74af082016-02-10 16:12:47 -0800251 "Bluetooth connected");
Christine Hallstrom96a0be62016-11-30 16:05:13 -0800252 addedRoutes |= ROUTE_BLUETOOTH;
253 break;
Hall Liuf62630a2015-10-27 14:53:39 -0700254 case DISCONNECT_WIRED_HEADSET:
Brad Ebingera3eccfe2016-10-05 15:45:22 -0700255 Log.addEvent(mCallsManager.getForegroundCall(), LogUtils.Events.AUDIO_ROUTE,
Hall Liuf62630a2015-10-27 14:53:39 -0700256 "Wired headset disconnected");
Christine Hallstrom96a0be62016-11-30 16:05:13 -0800257 removedRoutes |= ROUTE_WIRED_HEADSET;
Hall Liua3e9dda2015-12-15 17:52:50 -0800258 if (mDoesDeviceSupportEarpieceRoute) {
Christine Hallstrom96a0be62016-11-30 16:05:13 -0800259 addedRoutes |= ROUTE_EARPIECE;
Hall Liua3e9dda2015-12-15 17:52:50 -0800260 }
Christine Hallstrom96a0be62016-11-30 16:05:13 -0800261 break;
Hall Liuf62630a2015-10-27 14:53:39 -0700262 case DISCONNECT_BLUETOOTH:
Brad Ebingera3eccfe2016-10-05 15:45:22 -0700263 Log.addEvent(mCallsManager.getForegroundCall(), LogUtils.Events.AUDIO_ROUTE,
Hall Liue74af082016-02-10 16:12:47 -0800264 "Bluetooth disconnected");
Christine Hallstrom96a0be62016-11-30 16:05:13 -0800265 removedRoutes |= ROUTE_BLUETOOTH;
266 break;
Hall Liu132a5572017-11-02 18:44:57 -0700267 case BLUETOOTH_DEVICE_LIST_CHANGED:
268 Log.addEvent(mCallsManager.getForegroundCall(), LogUtils.Events.AUDIO_ROUTE,
269 "Bluetooth device list changed");
270 Collection<BluetoothDevice> connectedDevices =
271 mBluetoothRouteManager.getConnectedDevices();
272 if (connectedDevices.size() > 0) {
273 addedRoutes |= ROUTE_BLUETOOTH;
274 } else {
275 removedRoutes |= ROUTE_BLUETOOTH;
276 }
Hall Liu132a5572017-11-02 18:44:57 -0700277 isHandled = HANDLED;
278 break;
Hall Liua3e9dda2015-12-15 17:52:50 -0800279 case SWITCH_BASELINE_ROUTE:
Hall Liu95f2db92017-06-19 18:32:55 -0700280 sendInternalMessage(calculateBaselineRouteMessage(false,
281 msg.arg1 == INCLUDE_BLUETOOTH_IN_BASELINE));
Hall Liu4f296ba2016-02-18 14:46:57 -0800282 return HANDLED;
283 case USER_SWITCH_BASELINE_ROUTE:
Hall Liu95f2db92017-06-19 18:32:55 -0700284 sendInternalMessage(calculateBaselineRouteMessage(true,
285 msg.arg1 == INCLUDE_BLUETOOTH_IN_BASELINE));
Hall Liuf62630a2015-10-27 14:53:39 -0700286 return HANDLED;
Hall Liubf791402017-11-10 18:43:10 -0800287 case USER_SWITCH_BLUETOOTH:
288 // If the user tries to switch to BT, reset the explicitly-switched-away flag.
289 mHasUserExplicitlyLeftBluetooth = false;
290 return NOT_HANDLED;
Hall Liue271f222016-08-15 18:04:06 -0700291 case SWITCH_FOCUS:
292 mAudioFocusType = msg.arg1;
293 return NOT_HANDLED;
Hall Liuf62630a2015-10-27 14:53:39 -0700294 default:
295 return NOT_HANDLED;
296 }
Christine Hallstrom96a0be62016-11-30 16:05:13 -0800297
Hall Liubf791402017-11-10 18:43:10 -0800298 if (addedRoutes != 0 || removedRoutes != 0
299 || msg.what == BLUETOOTH_DEVICE_LIST_CHANGED) {
Christine Hallstrom96a0be62016-11-30 16:05:13 -0800300 mAvailableRoutes = modifyRoutes(mAvailableRoutes, removedRoutes, addedRoutes, true);
301 mDeviceSupportedRoutes = modifyRoutes(mDeviceSupportedRoutes, removedRoutes,
302 addedRoutes, false);
Hall Liubf791402017-11-10 18:43:10 -0800303 updateSystemAudioState();
Christine Hallstrom96a0be62016-11-30 16:05:13 -0800304 }
305
Hall Liu132a5572017-11-02 18:44:57 -0700306 return isHandled;
Hall Liuf62630a2015-10-27 14:53:39 -0700307 }
308
309 // Behavior will depend on whether the state is an active one or a quiescent one.
310 abstract public void updateSystemAudioState();
311 abstract public boolean isActive();
Hall Liu37f18d52017-08-18 14:20:26 -0700312 abstract public int getRouteCode();
Tyler Gunne04538f2017-11-17 15:18:47 -0800313
314 private String getVolumeString() {
315 if (mAudioManager == null) {
316 return "";
317 }
318 StringBuilder sb = new StringBuilder();
319 sb.append("Volume: rng=");
320 sb.append(mAudioManager.getStreamVolume(AudioManager.STREAM_RING));
321 sb.append(", call=");
322 sb.append(mAudioManager.getStreamVolume(AudioManager.STREAM_VOICE_CALL));
323 sb.append(", bt=");
324 sb.append(mAudioManager.getStreamVolume(AudioManager.STREAM_BLUETOOTH_SCO));
325 return sb.toString();
326 }
Hall Liuf62630a2015-10-27 14:53:39 -0700327 }
328
329 class ActiveEarpieceRoute extends EarpieceRoute {
330 @Override
331 public String getName() {
332 return ACTIVE_EARPIECE_ROUTE_NAME;
333 }
334
335 @Override
336 public boolean isActive() {
337 return true;
338 }
339
340 @Override
341 public void enter() {
342 super.enter();
343 setSpeakerphoneOn(false);
Hall Liu132a5572017-11-02 18:44:57 -0700344 setBluetoothOff();
Hall Liuf62630a2015-10-27 14:53:39 -0700345 CallAudioState newState = new CallAudioState(mIsMuted, ROUTE_EARPIECE,
Hall Liu9086fb12017-11-07 18:01:53 -0800346 mAvailableRoutes, null,
347 mBluetoothRouteManager.getConnectedDevices());
xulichengf86f4702017-02-28 13:51:57 +0800348 setSystemAudioState(newState, true);
Hall Liuf62630a2015-10-27 14:53:39 -0700349 updateInternalCallAudioState();
350 }
351
352 @Override
353 public void updateSystemAudioState() {
Hall Liuf62630a2015-10-27 14:53:39 -0700354 updateInternalCallAudioState();
Hall Liud109afb2016-01-26 12:53:53 -0800355 setSystemAudioState(mCurrentCallAudioState);
Hall Liuf62630a2015-10-27 14:53:39 -0700356 }
357
358 @Override
Brad Ebinger11623a32015-11-25 13:52:02 -0800359 public boolean processMessage(Message msg) {
360 if (super.processMessage(msg) == HANDLED) {
Hall Liuf62630a2015-10-27 14:53:39 -0700361 return HANDLED;
362 }
363 switch (msg.what) {
364 case SWITCH_EARPIECE:
Hall Liu4f296ba2016-02-18 14:46:57 -0800365 case USER_SWITCH_EARPIECE:
Hall Liuf62630a2015-10-27 14:53:39 -0700366 // Nothing to do here
367 return HANDLED;
Hall Liu132a5572017-11-02 18:44:57 -0700368 case BT_AUDIO_CONNECTED:
369 transitionTo(mActiveBluetoothRoute);
370 return HANDLED;
Hall Liuf62630a2015-10-27 14:53:39 -0700371 case SWITCH_BLUETOOTH:
Hall Liu4f296ba2016-02-18 14:46:57 -0800372 case USER_SWITCH_BLUETOOTH:
Hall Liuf62630a2015-10-27 14:53:39 -0700373 if ((mAvailableRoutes & ROUTE_BLUETOOTH) != 0) {
Hall Liu132a5572017-11-02 18:44:57 -0700374 if (mAudioFocusType == ACTIVE_FOCUS || mIsInbandRingSupported) {
Hall Liu9086fb12017-11-07 18:01:53 -0800375 String address = (msg.obj instanceof SomeArgs) ?
376 (String) ((SomeArgs) msg.obj).arg2 : null;
Hall Liu132a5572017-11-02 18:44:57 -0700377 // Omit transition to ActiveBluetoothRoute
Hall Liu9086fb12017-11-07 18:01:53 -0800378 setBluetoothOn(address);
Hall Liu132a5572017-11-02 18:44:57 -0700379 } else {
380 transitionTo(mRingingBluetoothRoute);
381 }
Hall Liuf62630a2015-10-27 14:53:39 -0700382 } else {
383 Log.w(this, "Ignoring switch to bluetooth command. Not available.");
384 }
385 return HANDLED;
386 case SWITCH_HEADSET:
Hall Liu4f296ba2016-02-18 14:46:57 -0800387 case USER_SWITCH_HEADSET:
Hall Liuf62630a2015-10-27 14:53:39 -0700388 if ((mAvailableRoutes & ROUTE_WIRED_HEADSET) != 0) {
389 transitionTo(mActiveHeadsetRoute);
390 } else {
391 Log.w(this, "Ignoring switch to headset command. Not available.");
392 }
393 return HANDLED;
394 case SWITCH_SPEAKER:
Hall Liu4f296ba2016-02-18 14:46:57 -0800395 case USER_SWITCH_SPEAKER:
Hall Liuf62630a2015-10-27 14:53:39 -0700396 transitionTo(mActiveSpeakerRoute);
397 return HANDLED;
398 case SWITCH_FOCUS:
399 if (msg.arg1 == NO_FOCUS) {
Hall Liud8ca5452016-03-10 14:53:15 -0800400 reinitialize();
Hall Liuf62630a2015-10-27 14:53:39 -0700401 }
402 return HANDLED;
403 default:
404 return NOT_HANDLED;
405 }
406 }
407 }
408
409 class QuiescentEarpieceRoute extends EarpieceRoute {
410 @Override
411 public String getName() {
412 return QUIESCENT_EARPIECE_ROUTE_NAME;
413 }
414
415 @Override
416 public boolean isActive() {
417 return false;
418 }
419
420 @Override
421 public void enter() {
422 super.enter();
Hall Liu4f296ba2016-02-18 14:46:57 -0800423 mHasUserExplicitlyLeftBluetooth = false;
Hall Liuf62630a2015-10-27 14:53:39 -0700424 updateInternalCallAudioState();
425 }
426
427 @Override
428 public void updateSystemAudioState() {
429 updateInternalCallAudioState();
430 }
431
432 @Override
Brad Ebinger11623a32015-11-25 13:52:02 -0800433 public boolean processMessage(Message msg) {
434 if (super.processMessage(msg) == HANDLED) {
Hall Liuf62630a2015-10-27 14:53:39 -0700435 return HANDLED;
436 }
437 switch (msg.what) {
438 case SWITCH_EARPIECE:
Garik Badalyan967bdfe2016-05-05 16:01:21 -0700439 case USER_SWITCH_EARPIECE:
Hall Liuf62630a2015-10-27 14:53:39 -0700440 // Nothing to do here
441 return HANDLED;
Hall Liu132a5572017-11-02 18:44:57 -0700442 case BT_AUDIO_CONNECTED:
443 Log.w(this, "BT Audio came on in quiescent earpiece route.");
444 transitionTo(mActiveBluetoothRoute);
445 return HANDLED;
Hall Liuf62630a2015-10-27 14:53:39 -0700446 case SWITCH_BLUETOOTH:
Garik Badalyan967bdfe2016-05-05 16:01:21 -0700447 case USER_SWITCH_BLUETOOTH:
Hall Liuf62630a2015-10-27 14:53:39 -0700448 if ((mAvailableRoutes & ROUTE_BLUETOOTH) != 0) {
449 transitionTo(mQuiescentBluetoothRoute);
450 } else {
451 Log.w(this, "Ignoring switch to bluetooth command. Not available.");
452 }
453 return HANDLED;
454 case SWITCH_HEADSET:
Garik Badalyan967bdfe2016-05-05 16:01:21 -0700455 case USER_SWITCH_HEADSET:
Hall Liuf62630a2015-10-27 14:53:39 -0700456 if ((mAvailableRoutes & ROUTE_WIRED_HEADSET) != 0) {
457 transitionTo(mQuiescentHeadsetRoute);
458 } else {
459 Log.w(this, "Ignoring switch to headset command. Not available.");
460 }
461 return HANDLED;
462 case SWITCH_SPEAKER:
Garik Badalyan967bdfe2016-05-05 16:01:21 -0700463 case USER_SWITCH_SPEAKER:
Hall Liuf62630a2015-10-27 14:53:39 -0700464 transitionTo(mQuiescentSpeakerRoute);
465 return HANDLED;
466 case SWITCH_FOCUS:
Hall Liue271f222016-08-15 18:04:06 -0700467 if (msg.arg1 == ACTIVE_FOCUS || msg.arg1 == RINGING_FOCUS) {
Hall Liuf62630a2015-10-27 14:53:39 -0700468 transitionTo(mActiveEarpieceRoute);
469 }
470 return HANDLED;
471 default:
472 return NOT_HANDLED;
473 }
474 }
475 }
476
477 abstract class EarpieceRoute extends AudioState {
478 @Override
Hall Liu37f18d52017-08-18 14:20:26 -0700479 public int getRouteCode() {
480 return CallAudioState.ROUTE_EARPIECE;
481 }
482
483 @Override
Brad Ebinger11623a32015-11-25 13:52:02 -0800484 public boolean processMessage(Message msg) {
485 if (super.processMessage(msg) == HANDLED) {
Hall Liuf62630a2015-10-27 14:53:39 -0700486 return HANDLED;
487 }
488 switch (msg.what) {
489 case CONNECT_WIRED_HEADSET:
490 sendInternalMessage(SWITCH_HEADSET);
491 return HANDLED;
492 case CONNECT_BLUETOOTH:
Hall Liu4f296ba2016-02-18 14:46:57 -0800493 if (!mHasUserExplicitlyLeftBluetooth) {
494 sendInternalMessage(SWITCH_BLUETOOTH);
495 } else {
Hall Liue74af082016-02-10 16:12:47 -0800496 Log.i(this, "Not switching to BT route from earpiece because user has " +
497 "explicitly disconnected.");
Hall Liu4f296ba2016-02-18 14:46:57 -0800498 }
Hall Liuf62630a2015-10-27 14:53:39 -0700499 return HANDLED;
500 case DISCONNECT_BLUETOOTH:
Hall Liuf62630a2015-10-27 14:53:39 -0700501 // No change in audio route required
502 return HANDLED;
503 case DISCONNECT_WIRED_HEADSET:
504 Log.e(this, new IllegalStateException(),
505 "Wired headset should not go from connected to not when on " +
506 "earpiece");
Hall Liuf62630a2015-10-27 14:53:39 -0700507 return HANDLED;
Hall Liu132a5572017-11-02 18:44:57 -0700508 case BT_AUDIO_DISCONNECTED:
Hall Liue74af082016-02-10 16:12:47 -0800509 // This may be sent as a confirmation by the BT stack after switch off BT.
510 return HANDLED;
Hall Liuf62630a2015-10-27 14:53:39 -0700511 case CONNECT_DOCK:
512 sendInternalMessage(SWITCH_SPEAKER);
513 return HANDLED;
514 case DISCONNECT_DOCK:
515 // Nothing to do here
516 return HANDLED;
517 default:
518 return NOT_HANDLED;
519 }
520 }
521 }
522
523 class ActiveHeadsetRoute extends HeadsetRoute {
524 @Override
525 public String getName() {
526 return ACTIVE_HEADSET_ROUTE_NAME;
527 }
528
529 @Override
530 public boolean isActive() {
531 return true;
532 }
533
534 @Override
535 public void enter() {
536 super.enter();
537 setSpeakerphoneOn(false);
Hall Liu132a5572017-11-02 18:44:57 -0700538 setBluetoothOff();
Hall Liuf62630a2015-10-27 14:53:39 -0700539 CallAudioState newState = new CallAudioState(mIsMuted, ROUTE_WIRED_HEADSET,
Hall Liu9086fb12017-11-07 18:01:53 -0800540 mAvailableRoutes, null, mBluetoothRouteManager.getConnectedDevices());
xulichengf86f4702017-02-28 13:51:57 +0800541 setSystemAudioState(newState, true);
Hall Liuf62630a2015-10-27 14:53:39 -0700542 updateInternalCallAudioState();
543 }
544
545 @Override
546 public void updateSystemAudioState() {
Hall Liuf62630a2015-10-27 14:53:39 -0700547 updateInternalCallAudioState();
Hall Liud109afb2016-01-26 12:53:53 -0800548 setSystemAudioState(mCurrentCallAudioState);
Hall Liuf62630a2015-10-27 14:53:39 -0700549 }
550
551 @Override
Brad Ebinger11623a32015-11-25 13:52:02 -0800552 public boolean processMessage(Message msg) {
553 if (super.processMessage(msg) == HANDLED) {
Hall Liuf62630a2015-10-27 14:53:39 -0700554 return HANDLED;
555 }
556 switch (msg.what) {
557 case SWITCH_EARPIECE:
Hall Liu4f296ba2016-02-18 14:46:57 -0800558 case USER_SWITCH_EARPIECE:
Hall Liuf62630a2015-10-27 14:53:39 -0700559 if ((mAvailableRoutes & ROUTE_EARPIECE) != 0) {
560 transitionTo(mActiveEarpieceRoute);
561 } else {
562 Log.w(this, "Ignoring switch to earpiece command. Not available.");
563 }
564 return HANDLED;
Hall Liu132a5572017-11-02 18:44:57 -0700565 case BT_AUDIO_CONNECTED:
566 transitionTo(mActiveBluetoothRoute);
567 return HANDLED;
Hall Liuf62630a2015-10-27 14:53:39 -0700568 case SWITCH_BLUETOOTH:
Hall Liu4f296ba2016-02-18 14:46:57 -0800569 case USER_SWITCH_BLUETOOTH:
Hall Liuf62630a2015-10-27 14:53:39 -0700570 if ((mAvailableRoutes & ROUTE_BLUETOOTH) != 0) {
Hall Liu132a5572017-11-02 18:44:57 -0700571 if (mAudioFocusType == ACTIVE_FOCUS || mIsInbandRingSupported) {
Hall Liu9086fb12017-11-07 18:01:53 -0800572 String address = (msg.obj instanceof SomeArgs) ?
573 (String) ((SomeArgs) msg.obj).arg2 : null;
Hall Liu132a5572017-11-02 18:44:57 -0700574 // Omit transition to ActiveBluetoothRoute until actual connection.
Hall Liu9086fb12017-11-07 18:01:53 -0800575 setBluetoothOn(address);
Hall Liu132a5572017-11-02 18:44:57 -0700576 } else {
577 transitionTo(mRingingBluetoothRoute);
578 }
Hall Liuf62630a2015-10-27 14:53:39 -0700579 } else {
580 Log.w(this, "Ignoring switch to bluetooth command. Not available.");
581 }
582 return HANDLED;
583 case SWITCH_HEADSET:
Hall Liu4f296ba2016-02-18 14:46:57 -0800584 case USER_SWITCH_HEADSET:
Hall Liuf62630a2015-10-27 14:53:39 -0700585 // Nothing to do
586 return HANDLED;
587 case SWITCH_SPEAKER:
Hall Liu4f296ba2016-02-18 14:46:57 -0800588 case USER_SWITCH_SPEAKER:
Hall Liuf62630a2015-10-27 14:53:39 -0700589 transitionTo(mActiveSpeakerRoute);
590 return HANDLED;
591 case SWITCH_FOCUS:
592 if (msg.arg1 == NO_FOCUS) {
Hall Liud8ca5452016-03-10 14:53:15 -0800593 reinitialize();
Hall Liuf62630a2015-10-27 14:53:39 -0700594 }
595 return HANDLED;
596 default:
597 return NOT_HANDLED;
598 }
599 }
600 }
601
602 class QuiescentHeadsetRoute extends HeadsetRoute {
603 @Override
604 public String getName() {
605 return QUIESCENT_HEADSET_ROUTE_NAME;
606 }
607
608 @Override
609 public boolean isActive() {
610 return false;
611 }
612
613 @Override
614 public void enter() {
615 super.enter();
Hall Liu4f296ba2016-02-18 14:46:57 -0800616 mHasUserExplicitlyLeftBluetooth = false;
Hall Liuf62630a2015-10-27 14:53:39 -0700617 updateInternalCallAudioState();
618 }
619
620 @Override
621 public void updateSystemAudioState() {
622 updateInternalCallAudioState();
623 }
624
625 @Override
Brad Ebinger11623a32015-11-25 13:52:02 -0800626 public boolean processMessage(Message msg) {
627 if (super.processMessage(msg) == HANDLED) {
Hall Liuf62630a2015-10-27 14:53:39 -0700628 return HANDLED;
629 }
630 switch (msg.what) {
631 case SWITCH_EARPIECE:
Garik Badalyan967bdfe2016-05-05 16:01:21 -0700632 case USER_SWITCH_EARPIECE:
Hall Liuf62630a2015-10-27 14:53:39 -0700633 if ((mAvailableRoutes & ROUTE_EARPIECE) != 0) {
634 transitionTo(mQuiescentEarpieceRoute);
635 } else {
636 Log.w(this, "Ignoring switch to earpiece command. Not available.");
637 }
638 return HANDLED;
Hall Liu132a5572017-11-02 18:44:57 -0700639 case BT_AUDIO_CONNECTED:
640 transitionTo(mActiveBluetoothRoute);
641 Log.w(this, "BT Audio came on in quiescent headset route.");
642 return HANDLED;
Hall Liuf62630a2015-10-27 14:53:39 -0700643 case SWITCH_BLUETOOTH:
Garik Badalyan967bdfe2016-05-05 16:01:21 -0700644 case USER_SWITCH_BLUETOOTH:
Hall Liuf62630a2015-10-27 14:53:39 -0700645 if ((mAvailableRoutes & ROUTE_BLUETOOTH) != 0) {
646 transitionTo(mQuiescentBluetoothRoute);
647 } else {
648 Log.w(this, "Ignoring switch to bluetooth command. Not available.");
649 }
650 return HANDLED;
651 case SWITCH_HEADSET:
Garik Badalyan967bdfe2016-05-05 16:01:21 -0700652 case USER_SWITCH_HEADSET:
Hall Liuf62630a2015-10-27 14:53:39 -0700653 // Nothing to do
654 return HANDLED;
655 case SWITCH_SPEAKER:
Garik Badalyan967bdfe2016-05-05 16:01:21 -0700656 case USER_SWITCH_SPEAKER:
Hall Liuf62630a2015-10-27 14:53:39 -0700657 transitionTo(mQuiescentSpeakerRoute);
658 return HANDLED;
659 case SWITCH_FOCUS:
Hall Liue271f222016-08-15 18:04:06 -0700660 if (msg.arg1 == ACTIVE_FOCUS || msg.arg1 == RINGING_FOCUS) {
Hall Liuf62630a2015-10-27 14:53:39 -0700661 transitionTo(mActiveHeadsetRoute);
662 }
663 return HANDLED;
664 default:
665 return NOT_HANDLED;
666 }
667 }
668 }
669
670 abstract class HeadsetRoute extends AudioState {
671 @Override
Hall Liu37f18d52017-08-18 14:20:26 -0700672 public int getRouteCode() {
673 return CallAudioState.ROUTE_WIRED_HEADSET;
674 }
675
676 @Override
Brad Ebinger11623a32015-11-25 13:52:02 -0800677 public boolean processMessage(Message msg) {
678 if (super.processMessage(msg) == HANDLED) {
Hall Liuf62630a2015-10-27 14:53:39 -0700679 return HANDLED;
680 }
681 switch (msg.what) {
682 case CONNECT_WIRED_HEADSET:
683 Log.e(this, new IllegalStateException(),
684 "Wired headset should already be connected.");
Hall Liuf62630a2015-10-27 14:53:39 -0700685 return HANDLED;
686 case CONNECT_BLUETOOTH:
Hall Liu4f296ba2016-02-18 14:46:57 -0800687 if (!mHasUserExplicitlyLeftBluetooth) {
688 sendInternalMessage(SWITCH_BLUETOOTH);
689 } else {
Hall Liue74af082016-02-10 16:12:47 -0800690 Log.i(this, "Not switching to BT route from headset because user has " +
691 "explicitly disconnected.");
Hall Liu4f296ba2016-02-18 14:46:57 -0800692 }
Hall Liuf62630a2015-10-27 14:53:39 -0700693 return HANDLED;
694 case DISCONNECT_BLUETOOTH:
Hall Liuf62630a2015-10-27 14:53:39 -0700695 // No change in audio route required
696 return HANDLED;
697 case DISCONNECT_WIRED_HEADSET:
698 if (mWasOnSpeaker) {
699 sendInternalMessage(SWITCH_SPEAKER);
700 } else {
Hall Liu95f2db92017-06-19 18:32:55 -0700701 sendInternalMessage(SWITCH_BASELINE_ROUTE, INCLUDE_BLUETOOTH_IN_BASELINE);
Hall Liuf62630a2015-10-27 14:53:39 -0700702 }
703 return HANDLED;
Hall Liu132a5572017-11-02 18:44:57 -0700704 case BT_AUDIO_DISCONNECTED:
Hall Liue74af082016-02-10 16:12:47 -0800705 // This may be sent as a confirmation by the BT stack after switch off BT.
706 return HANDLED;
Hall Liuf62630a2015-10-27 14:53:39 -0700707 case CONNECT_DOCK:
708 // Nothing to do here
709 return HANDLED;
710 case DISCONNECT_DOCK:
711 // Nothing to do here
712 return HANDLED;
713 default:
714 return NOT_HANDLED;
715 }
716 }
717 }
718
Hall Liu132a5572017-11-02 18:44:57 -0700719 // Note: transitions to/from this class work a bit differently -- we delegate to
720 // BluetoothRouteManager to manage all Bluetooth state, so instead of transitioning to one of
721 // the bluetooth states immediately when there's an request to do so, we wait for
722 // BluetoothRouteManager to report its state before we go into this state.
Hall Liuf62630a2015-10-27 14:53:39 -0700723 class ActiveBluetoothRoute extends BluetoothRoute {
724 @Override
725 public String getName() {
726 return ACTIVE_BLUETOOTH_ROUTE_NAME;
727 }
728
729 @Override
730 public boolean isActive() {
731 return true;
732 }
733
734 @Override
735 public void enter() {
736 super.enter();
737 setSpeakerphoneOn(false);
Hall Liuf62630a2015-10-27 14:53:39 -0700738 CallAudioState newState = new CallAudioState(mIsMuted, ROUTE_BLUETOOTH,
Hall Liu9086fb12017-11-07 18:01:53 -0800739 mAvailableRoutes, mBluetoothRouteManager.getBluetoothAudioConnectedDevice(),
740 mBluetoothRouteManager.getConnectedDevices());
xulichengf86f4702017-02-28 13:51:57 +0800741 setSystemAudioState(newState, true);
Hall Liuf62630a2015-10-27 14:53:39 -0700742 updateInternalCallAudioState();
743 }
744
745 @Override
746 public void updateSystemAudioState() {
Hall Liuf62630a2015-10-27 14:53:39 -0700747 updateInternalCallAudioState();
Hall Liud109afb2016-01-26 12:53:53 -0800748 setSystemAudioState(mCurrentCallAudioState);
Hall Liuf62630a2015-10-27 14:53:39 -0700749 }
750
751 @Override
Brad Ebinger11623a32015-11-25 13:52:02 -0800752 public boolean processMessage(Message msg) {
753 if (super.processMessage(msg) == HANDLED) {
Hall Liuf62630a2015-10-27 14:53:39 -0700754 return HANDLED;
755 }
756 switch (msg.what) {
Hall Liu4f296ba2016-02-18 14:46:57 -0800757 case USER_SWITCH_EARPIECE:
758 mHasUserExplicitlyLeftBluetooth = true;
759 // fall through
Hall Liuf62630a2015-10-27 14:53:39 -0700760 case SWITCH_EARPIECE:
761 if ((mAvailableRoutes & ROUTE_EARPIECE) != 0) {
762 transitionTo(mActiveEarpieceRoute);
763 } else {
764 Log.w(this, "Ignoring switch to earpiece command. Not available.");
765 }
766 return HANDLED;
Hall Liu132a5572017-11-02 18:44:57 -0700767 case BT_AUDIO_CONNECTED:
Hall Liu9086fb12017-11-07 18:01:53 -0800768 // Nothing to do
769 return HANDLED;
Hall Liuf62630a2015-10-27 14:53:39 -0700770 case SWITCH_BLUETOOTH:
Hall Liu4f296ba2016-02-18 14:46:57 -0800771 case USER_SWITCH_BLUETOOTH:
Hall Liu9086fb12017-11-07 18:01:53 -0800772 String address = (msg.obj instanceof SomeArgs) ?
773 (String) ((SomeArgs) msg.obj).arg2 : null;
774 setBluetoothOn(address);
Hall Liuf62630a2015-10-27 14:53:39 -0700775 return HANDLED;
Hall Liu4f296ba2016-02-18 14:46:57 -0800776 case USER_SWITCH_HEADSET:
777 mHasUserExplicitlyLeftBluetooth = true;
778 // fall through
Hall Liuf62630a2015-10-27 14:53:39 -0700779 case SWITCH_HEADSET:
780 if ((mAvailableRoutes & ROUTE_WIRED_HEADSET) != 0) {
781 transitionTo(mActiveHeadsetRoute);
782 } else {
783 Log.w(this, "Ignoring switch to headset command. Not available.");
784 }
785 return HANDLED;
Hall Liu4f296ba2016-02-18 14:46:57 -0800786 case USER_SWITCH_SPEAKER:
787 mHasUserExplicitlyLeftBluetooth = true;
788 // fall through
Hall Liuf62630a2015-10-27 14:53:39 -0700789 case SWITCH_SPEAKER:
790 transitionTo(mActiveSpeakerRoute);
791 return HANDLED;
792 case SWITCH_FOCUS:
793 if (msg.arg1 == NO_FOCUS) {
Hall Liu132a5572017-11-02 18:44:57 -0700794 setBluetoothOff();
Hall Liud8ca5452016-03-10 14:53:15 -0800795 reinitialize();
Hall Liu132a5572017-11-02 18:44:57 -0700796 } else if (msg.arg1 == RINGING_FOCUS && !mIsInbandRingSupported) {
797 setBluetoothOff();
Hall Liue271f222016-08-15 18:04:06 -0700798 transitionTo(mRingingBluetoothRoute);
Hall Liuf62630a2015-10-27 14:53:39 -0700799 }
800 return HANDLED;
Hall Liu132a5572017-11-02 18:44:57 -0700801 case BT_AUDIO_DISCONNECTED:
Hall Liu95f2db92017-06-19 18:32:55 -0700802 sendInternalMessage(SWITCH_BASELINE_ROUTE, NO_INCLUDE_BLUETOOTH_IN_BASELINE);
Hall Liu147cc5f2016-04-25 14:29:19 -0700803 return HANDLED;
Hall Liuf62630a2015-10-27 14:53:39 -0700804 default:
805 return NOT_HANDLED;
806 }
807 }
808 }
809
Hall Liu132a5572017-11-02 18:44:57 -0700810 // This state is only used when the device doesn't support in-band ring. If it does,
811 // ActiveBluetoothRoute is used instead.
Hall Liue271f222016-08-15 18:04:06 -0700812 class RingingBluetoothRoute extends BluetoothRoute {
813 @Override
814 public String getName() {
815 return RINGING_BLUETOOTH_ROUTE_NAME;
816 }
817
818 @Override
819 public boolean isActive() {
820 return false;
821 }
822
823 @Override
824 public void enter() {
825 super.enter();
826 setSpeakerphoneOn(false);
827 // Do not enable SCO audio here, since RING is being sent to the headset.
828 CallAudioState newState = new CallAudioState(mIsMuted, ROUTE_BLUETOOTH,
Hall Liu9086fb12017-11-07 18:01:53 -0800829 mAvailableRoutes, mBluetoothRouteManager.getBluetoothAudioConnectedDevice(),
830 mBluetoothRouteManager.getConnectedDevices());
Hall Liue271f222016-08-15 18:04:06 -0700831 setSystemAudioState(newState);
832 updateInternalCallAudioState();
833 }
834
835 @Override
836 public void updateSystemAudioState() {
837 updateInternalCallAudioState();
838 setSystemAudioState(mCurrentCallAudioState);
839 }
840
841 @Override
842 public boolean processMessage(Message msg) {
843 if (super.processMessage(msg) == HANDLED) {
844 return HANDLED;
845 }
846 switch (msg.what) {
847 case USER_SWITCH_EARPIECE:
848 mHasUserExplicitlyLeftBluetooth = true;
849 // fall through
850 case SWITCH_EARPIECE:
851 if ((mAvailableRoutes & ROUTE_EARPIECE) != 0) {
852 transitionTo(mActiveEarpieceRoute);
853 } else {
854 Log.w(this, "Ignoring switch to earpiece command. Not available.");
855 }
856 return HANDLED;
Hall Liu132a5572017-11-02 18:44:57 -0700857 case BT_AUDIO_CONNECTED:
858 transitionTo(mActiveBluetoothRoute);
859 return HANDLED;
Hall Liue271f222016-08-15 18:04:06 -0700860 case SWITCH_BLUETOOTH:
861 case USER_SWITCH_BLUETOOTH:
862 // Nothing to do
863 return HANDLED;
864 case USER_SWITCH_HEADSET:
865 mHasUserExplicitlyLeftBluetooth = true;
866 // fall through
867 case SWITCH_HEADSET:
868 if ((mAvailableRoutes & ROUTE_WIRED_HEADSET) != 0) {
869 transitionTo(mActiveHeadsetRoute);
870 } else {
871 Log.w(this, "Ignoring switch to headset command. Not available.");
872 }
873 return HANDLED;
874 case USER_SWITCH_SPEAKER:
875 mHasUserExplicitlyLeftBluetooth = true;
876 // fall through
877 case SWITCH_SPEAKER:
878 transitionTo(mActiveSpeakerRoute);
879 return HANDLED;
880 case SWITCH_FOCUS:
881 if (msg.arg1 == NO_FOCUS) {
882 reinitialize();
883 } else if (msg.arg1 == ACTIVE_FOCUS) {
Hall Liu9086fb12017-11-07 18:01:53 -0800884 setBluetoothOn(null);
Hall Liue271f222016-08-15 18:04:06 -0700885 }
886 return HANDLED;
Hall Liu132a5572017-11-02 18:44:57 -0700887 case BT_AUDIO_DISCONNECTED:
888 // Ignore this -- audio disconnecting while ringing w/o in-band should not
889 // cause a route switch, since the device is still connected.
Hall Liue271f222016-08-15 18:04:06 -0700890 return HANDLED;
891 default:
892 return NOT_HANDLED;
893 }
894 }
895 }
896
Hall Liuf62630a2015-10-27 14:53:39 -0700897 class QuiescentBluetoothRoute extends BluetoothRoute {
898 @Override
899 public String getName() {
900 return QUIESCENT_BLUETOOTH_ROUTE_NAME;
901 }
902
903 @Override
904 public boolean isActive() {
905 return false;
906 }
907
908 @Override
909 public void enter() {
910 super.enter();
Hall Liu4f296ba2016-02-18 14:46:57 -0800911 mHasUserExplicitlyLeftBluetooth = false;
Hall Liuf62630a2015-10-27 14:53:39 -0700912 updateInternalCallAudioState();
913 }
914
915 @Override
916 public void updateSystemAudioState() {
917 updateInternalCallAudioState();
918 }
919
920 @Override
Brad Ebinger11623a32015-11-25 13:52:02 -0800921 public boolean processMessage(Message msg) {
922 if (super.processMessage(msg) == HANDLED) {
Hall Liuf62630a2015-10-27 14:53:39 -0700923 return HANDLED;
924 }
925 switch (msg.what) {
926 case SWITCH_EARPIECE:
Garik Badalyan967bdfe2016-05-05 16:01:21 -0700927 case USER_SWITCH_EARPIECE:
Hall Liuf62630a2015-10-27 14:53:39 -0700928 if ((mAvailableRoutes & ROUTE_EARPIECE) != 0) {
929 transitionTo(mQuiescentEarpieceRoute);
930 } else {
931 Log.w(this, "Ignoring switch to earpiece command. Not available.");
932 }
933 return HANDLED;
Hall Liu132a5572017-11-02 18:44:57 -0700934 case BT_AUDIO_CONNECTED:
935 transitionTo(mActiveBluetoothRoute);
936 return HANDLED;
Hall Liuf62630a2015-10-27 14:53:39 -0700937 case SWITCH_BLUETOOTH:
Garik Badalyan967bdfe2016-05-05 16:01:21 -0700938 case USER_SWITCH_BLUETOOTH:
Hall Liuf62630a2015-10-27 14:53:39 -0700939 // Nothing to do
940 return HANDLED;
941 case SWITCH_HEADSET:
Garik Badalyan967bdfe2016-05-05 16:01:21 -0700942 case USER_SWITCH_HEADSET:
Hall Liuf62630a2015-10-27 14:53:39 -0700943 if ((mAvailableRoutes & ROUTE_WIRED_HEADSET) != 0) {
944 transitionTo(mQuiescentHeadsetRoute);
945 } else {
946 Log.w(this, "Ignoring switch to headset command. Not available.");
947 }
948 return HANDLED;
949 case SWITCH_SPEAKER:
Garik Badalyan967bdfe2016-05-05 16:01:21 -0700950 case USER_SWITCH_SPEAKER:
Hall Liuf62630a2015-10-27 14:53:39 -0700951 transitionTo(mQuiescentSpeakerRoute);
952 return HANDLED;
953 case SWITCH_FOCUS:
Hall Liue271f222016-08-15 18:04:06 -0700954 if (msg.arg1 == ACTIVE_FOCUS) {
Hall Liu9086fb12017-11-07 18:01:53 -0800955 setBluetoothOn(null);
Hall Liue271f222016-08-15 18:04:06 -0700956 } else if (msg.arg1 == RINGING_FOCUS) {
Hall Liu132a5572017-11-02 18:44:57 -0700957 if (mIsInbandRingSupported) {
Hall Liu9086fb12017-11-07 18:01:53 -0800958 setBluetoothOn(null);
Hall Liu132a5572017-11-02 18:44:57 -0700959 } else {
960 transitionTo(mRingingBluetoothRoute);
961 }
Hall Liuf62630a2015-10-27 14:53:39 -0700962 }
963 return HANDLED;
Hall Liu132a5572017-11-02 18:44:57 -0700964 case BT_AUDIO_DISCONNECTED:
Hall Liu147cc5f2016-04-25 14:29:19 -0700965 // Ignore this -- audio disconnecting while quiescent should not cause a
966 // route switch, since the device is still connected.
967 return HANDLED;
Hall Liuf62630a2015-10-27 14:53:39 -0700968 default:
969 return NOT_HANDLED;
970 }
971 }
972 }
973
974 abstract class BluetoothRoute extends AudioState {
975 @Override
Hall Liu37f18d52017-08-18 14:20:26 -0700976 public int getRouteCode() {
977 return CallAudioState.ROUTE_BLUETOOTH;
978 }
979
980 @Override
Brad Ebinger11623a32015-11-25 13:52:02 -0800981 public boolean processMessage(Message msg) {
982 if (super.processMessage(msg) == HANDLED) {
Hall Liuf62630a2015-10-27 14:53:39 -0700983 return HANDLED;
984 }
985 switch (msg.what) {
986 case CONNECT_WIRED_HEADSET:
987 sendInternalMessage(SWITCH_HEADSET);
988 return HANDLED;
989 case CONNECT_BLUETOOTH:
990 // We can't tell when a change in bluetooth state corresponds to an
991 // actual connection or disconnection, so we'll just ignore it if we're already
992 // in the bluetooth route.
993 return HANDLED;
994 case DISCONNECT_BLUETOOTH:
Hall Liu95f2db92017-06-19 18:32:55 -0700995 sendInternalMessage(SWITCH_BASELINE_ROUTE, NO_INCLUDE_BLUETOOTH_IN_BASELINE);
Hall Liuf62630a2015-10-27 14:53:39 -0700996 mWasOnSpeaker = false;
997 return HANDLED;
998 case DISCONNECT_WIRED_HEADSET:
Hall Liuf62630a2015-10-27 14:53:39 -0700999 // No change in audio route required
1000 return HANDLED;
1001 case CONNECT_DOCK:
1002 // Nothing to do here
1003 return HANDLED;
1004 case DISCONNECT_DOCK:
1005 // Nothing to do here
1006 return HANDLED;
1007 default:
1008 return NOT_HANDLED;
1009 }
1010 }
1011 }
1012
1013 class ActiveSpeakerRoute extends SpeakerRoute {
1014 @Override
1015 public String getName() {
1016 return ACTIVE_SPEAKER_ROUTE_NAME;
1017 }
1018
1019 @Override
1020 public boolean isActive() {
1021 return true;
1022 }
1023
1024 @Override
1025 public void enter() {
1026 super.enter();
1027 mWasOnSpeaker = true;
1028 setSpeakerphoneOn(true);
Hall Liu132a5572017-11-02 18:44:57 -07001029 setBluetoothOff();
Hall Liuf62630a2015-10-27 14:53:39 -07001030 CallAudioState newState = new CallAudioState(mIsMuted, ROUTE_SPEAKER,
Hall Liu9086fb12017-11-07 18:01:53 -08001031 mAvailableRoutes, null, mBluetoothRouteManager.getConnectedDevices());
Hall Liubf791402017-11-10 18:43:10 -08001032 setSystemAudioState(newState, true);
Hall Liuf62630a2015-10-27 14:53:39 -07001033 updateInternalCallAudioState();
1034 }
1035
1036 @Override
1037 public void updateSystemAudioState() {
Hall Liuf62630a2015-10-27 14:53:39 -07001038 updateInternalCallAudioState();
Hall Liud109afb2016-01-26 12:53:53 -08001039 setSystemAudioState(mCurrentCallAudioState);
Hall Liuf62630a2015-10-27 14:53:39 -07001040 }
1041
1042 @Override
Brad Ebinger11623a32015-11-25 13:52:02 -08001043 public boolean processMessage(Message msg) {
1044 if (super.processMessage(msg) == HANDLED) {
Hall Liuf62630a2015-10-27 14:53:39 -07001045 return HANDLED;
1046 }
1047 switch(msg.what) {
Hall Liu4f296ba2016-02-18 14:46:57 -08001048 case USER_SWITCH_EARPIECE:
Hall Liu04209a32016-05-02 14:47:06 -07001049 mWasOnSpeaker = false;
1050 // fall through
1051 case SWITCH_EARPIECE:
Hall Liuf62630a2015-10-27 14:53:39 -07001052 if ((mAvailableRoutes & ROUTE_EARPIECE) != 0) {
1053 transitionTo(mActiveEarpieceRoute);
1054 } else {
1055 Log.w(this, "Ignoring switch to earpiece command. Not available.");
1056 }
1057 return HANDLED;
Hall Liu132a5572017-11-02 18:44:57 -07001058 case BT_AUDIO_CONNECTED:
1059 transitionTo(mActiveBluetoothRoute);
1060 return HANDLED;
Hall Liu4f296ba2016-02-18 14:46:57 -08001061 case USER_SWITCH_BLUETOOTH:
Hall Liu04209a32016-05-02 14:47:06 -07001062 mWasOnSpeaker = false;
1063 // fall through
1064 case SWITCH_BLUETOOTH:
Hall Liu9086fb12017-11-07 18:01:53 -08001065 String address = (msg.obj instanceof SomeArgs) ?
1066 (String) ((SomeArgs) msg.obj).arg2 : null;
Hall Liuf62630a2015-10-27 14:53:39 -07001067 if ((mAvailableRoutes & ROUTE_BLUETOOTH) != 0) {
Hall Liu132a5572017-11-02 18:44:57 -07001068 if (mAudioFocusType == ACTIVE_FOCUS || mIsInbandRingSupported) {
1069 // Omit transition to ActiveBluetoothRoute
Hall Liu9086fb12017-11-07 18:01:53 -08001070 setBluetoothOn(address);
Hall Liu132a5572017-11-02 18:44:57 -07001071 } else {
1072 transitionTo(mRingingBluetoothRoute);
1073 }
Hall Liuf62630a2015-10-27 14:53:39 -07001074 } else {
1075 Log.w(this, "Ignoring switch to bluetooth command. Not available.");
1076 }
1077 return HANDLED;
Hall Liu4f296ba2016-02-18 14:46:57 -08001078 case USER_SWITCH_HEADSET:
Hall Liu04209a32016-05-02 14:47:06 -07001079 mWasOnSpeaker = false;
1080 // fall through
1081 case SWITCH_HEADSET:
Hall Liuf62630a2015-10-27 14:53:39 -07001082 if ((mAvailableRoutes & ROUTE_WIRED_HEADSET) != 0) {
1083 transitionTo(mActiveHeadsetRoute);
1084 } else {
1085 Log.w(this, "Ignoring switch to headset command. Not available.");
1086 }
1087 return HANDLED;
1088 case SWITCH_SPEAKER:
Hall Liu4f296ba2016-02-18 14:46:57 -08001089 case USER_SWITCH_SPEAKER:
Hall Liuf62630a2015-10-27 14:53:39 -07001090 // Nothing to do
1091 return HANDLED;
1092 case SWITCH_FOCUS:
1093 if (msg.arg1 == NO_FOCUS) {
Hall Liud8ca5452016-03-10 14:53:15 -08001094 reinitialize();
Hall Liuf62630a2015-10-27 14:53:39 -07001095 }
1096 return HANDLED;
1097 default:
1098 return NOT_HANDLED;
1099 }
1100 }
1101 }
1102
1103 class QuiescentSpeakerRoute extends SpeakerRoute {
1104 @Override
1105 public String getName() {
1106 return QUIESCENT_SPEAKER_ROUTE_NAME;
1107 }
1108
1109 @Override
1110 public boolean isActive() {
1111 return false;
1112 }
1113
1114 @Override
1115 public void enter() {
1116 super.enter();
Hall Liu4f296ba2016-02-18 14:46:57 -08001117 mHasUserExplicitlyLeftBluetooth = false;
Hall Liuf62630a2015-10-27 14:53:39 -07001118 // Omit setting mWasOnSpeaker to true here, since this does not reflect a call
1119 // actually being on speakerphone.
1120 updateInternalCallAudioState();
1121 }
1122
1123 @Override
1124 public void updateSystemAudioState() {
1125 updateInternalCallAudioState();
1126 }
1127
1128 @Override
Brad Ebinger11623a32015-11-25 13:52:02 -08001129 public boolean processMessage(Message msg) {
1130 if (super.processMessage(msg) == HANDLED) {
Hall Liuf62630a2015-10-27 14:53:39 -07001131 return HANDLED;
1132 }
1133 switch(msg.what) {
1134 case SWITCH_EARPIECE:
Garik Badalyan967bdfe2016-05-05 16:01:21 -07001135 case USER_SWITCH_EARPIECE:
Hall Liuf62630a2015-10-27 14:53:39 -07001136 if ((mAvailableRoutes & ROUTE_EARPIECE) != 0) {
1137 transitionTo(mQuiescentEarpieceRoute);
1138 } else {
1139 Log.w(this, "Ignoring switch to earpiece command. Not available.");
1140 }
1141 return HANDLED;
Hall Liu132a5572017-11-02 18:44:57 -07001142 case BT_AUDIO_CONNECTED:
1143 transitionTo(mActiveBluetoothRoute);
1144 Log.w(this, "BT audio reported as connected while in quiescent speaker");
1145 return HANDLED;
Hall Liuf62630a2015-10-27 14:53:39 -07001146 case SWITCH_BLUETOOTH:
Garik Badalyan967bdfe2016-05-05 16:01:21 -07001147 case USER_SWITCH_BLUETOOTH:
Hall Liuf62630a2015-10-27 14:53:39 -07001148 if ((mAvailableRoutes & ROUTE_BLUETOOTH) != 0) {
1149 transitionTo(mQuiescentBluetoothRoute);
1150 } else {
1151 Log.w(this, "Ignoring switch to bluetooth command. Not available.");
1152 }
1153 return HANDLED;
1154 case SWITCH_HEADSET:
Garik Badalyan967bdfe2016-05-05 16:01:21 -07001155 case USER_SWITCH_HEADSET:
Hall Liuf62630a2015-10-27 14:53:39 -07001156 if ((mAvailableRoutes & ROUTE_WIRED_HEADSET) != 0) {
1157 transitionTo(mQuiescentHeadsetRoute);
1158 } else {
1159 Log.w(this, "Ignoring switch to headset command. Not available.");
1160 }
1161 return HANDLED;
1162 case SWITCH_SPEAKER:
Garik Badalyan967bdfe2016-05-05 16:01:21 -07001163 case USER_SWITCH_SPEAKER:
Hall Liuf62630a2015-10-27 14:53:39 -07001164 // Nothing to do
1165 return HANDLED;
1166 case SWITCH_FOCUS:
Hall Liue271f222016-08-15 18:04:06 -07001167 if (msg.arg1 == ACTIVE_FOCUS || msg.arg1 == RINGING_FOCUS) {
Hall Liuf62630a2015-10-27 14:53:39 -07001168 transitionTo(mActiveSpeakerRoute);
1169 }
1170 return HANDLED;
1171 default:
1172 return NOT_HANDLED;
1173 }
1174 }
1175 }
1176
1177 abstract class SpeakerRoute extends AudioState {
1178 @Override
Hall Liu37f18d52017-08-18 14:20:26 -07001179 public int getRouteCode() {
1180 return CallAudioState.ROUTE_SPEAKER;
1181 }
1182
1183 @Override
Brad Ebinger11623a32015-11-25 13:52:02 -08001184 public boolean processMessage(Message msg) {
1185 if (super.processMessage(msg) == HANDLED) {
Hall Liuf62630a2015-10-27 14:53:39 -07001186 return HANDLED;
1187 }
1188 switch (msg.what) {
1189 case CONNECT_WIRED_HEADSET:
1190 sendInternalMessage(SWITCH_HEADSET);
1191 return HANDLED;
1192 case CONNECT_BLUETOOTH:
Hall Liu4f296ba2016-02-18 14:46:57 -08001193 if (!mHasUserExplicitlyLeftBluetooth) {
1194 sendInternalMessage(SWITCH_BLUETOOTH);
1195 } else {
Hall Liue74af082016-02-10 16:12:47 -08001196 Log.i(this, "Not switching to BT route from speaker because user has " +
1197 "explicitly disconnected.");
Hall Liu4f296ba2016-02-18 14:46:57 -08001198 }
Hall Liuf62630a2015-10-27 14:53:39 -07001199 return HANDLED;
1200 case DISCONNECT_BLUETOOTH:
Hall Liuf62630a2015-10-27 14:53:39 -07001201 // No change in audio route required
1202 return HANDLED;
1203 case DISCONNECT_WIRED_HEADSET:
Hall Liuf62630a2015-10-27 14:53:39 -07001204 // No change in audio route required
1205 return HANDLED;
Hall Liu132a5572017-11-02 18:44:57 -07001206 case BT_AUDIO_DISCONNECTED:
Hall Liue74af082016-02-10 16:12:47 -08001207 // This may be sent as a confirmation by the BT stack after switch off BT.
1208 return HANDLED;
Hall Liuf62630a2015-10-27 14:53:39 -07001209 case CONNECT_DOCK:
1210 // Nothing to do here
1211 return HANDLED;
1212 case DISCONNECT_DOCK:
Hall Liu95f2db92017-06-19 18:32:55 -07001213 sendInternalMessage(SWITCH_BASELINE_ROUTE, INCLUDE_BLUETOOTH_IN_BASELINE);
Hall Liuf62630a2015-10-27 14:53:39 -07001214 return HANDLED;
1215 default:
1216 return NOT_HANDLED;
1217 }
1218 }
1219 }
1220
1221 private final ActiveEarpieceRoute mActiveEarpieceRoute = new ActiveEarpieceRoute();
1222 private final ActiveHeadsetRoute mActiveHeadsetRoute = new ActiveHeadsetRoute();
1223 private final ActiveBluetoothRoute mActiveBluetoothRoute = new ActiveBluetoothRoute();
1224 private final ActiveSpeakerRoute mActiveSpeakerRoute = new ActiveSpeakerRoute();
Hall Liue271f222016-08-15 18:04:06 -07001225 private final RingingBluetoothRoute mRingingBluetoothRoute = new RingingBluetoothRoute();
Hall Liuf62630a2015-10-27 14:53:39 -07001226 private final QuiescentEarpieceRoute mQuiescentEarpieceRoute = new QuiescentEarpieceRoute();
1227 private final QuiescentHeadsetRoute mQuiescentHeadsetRoute = new QuiescentHeadsetRoute();
1228 private final QuiescentBluetoothRoute mQuiescentBluetoothRoute = new QuiescentBluetoothRoute();
1229 private final QuiescentSpeakerRoute mQuiescentSpeakerRoute = new QuiescentSpeakerRoute();
1230
1231 /**
1232 * A few pieces of hidden state. Used to avoid exponential explosion of number of explicit
1233 * states
1234 */
Christine Hallstrom96a0be62016-11-30 16:05:13 -08001235 private int mDeviceSupportedRoutes;
Hall Liuf62630a2015-10-27 14:53:39 -07001236 private int mAvailableRoutes;
Hall Liue271f222016-08-15 18:04:06 -07001237 private int mAudioFocusType;
Hall Liuf62630a2015-10-27 14:53:39 -07001238 private boolean mWasOnSpeaker;
1239 private boolean mIsMuted;
1240
1241 private final Context mContext;
1242 private final CallsManager mCallsManager;
1243 private final AudioManager mAudioManager;
Hall Liu486cb192016-10-21 18:23:33 -07001244 private final BluetoothRouteManager mBluetoothRouteManager;
Hall Liuf62630a2015-10-27 14:53:39 -07001245 private final WiredHeadsetManager mWiredHeadsetManager;
1246 private final StatusBarNotifier mStatusBarNotifier;
1247 private final CallAudioManager.AudioServiceFactory mAudioServiceFactory;
Hall Liua3e9dda2015-12-15 17:52:50 -08001248 private final boolean mDoesDeviceSupportEarpieceRoute;
Hall Liu609992b2016-08-31 15:48:51 -07001249 private final TelecomSystem.SyncRoot mLock;
Hall Liu4f296ba2016-02-18 14:46:57 -08001250 private boolean mHasUserExplicitlyLeftBluetooth = false;
Hall Liuf62630a2015-10-27 14:53:39 -07001251
1252 private HashMap<String, Integer> mStateNameToRouteCode;
1253 private HashMap<Integer, AudioState> mRouteCodeToQuiescentState;
1254
1255 // CallAudioState is used as an interface to communicate with many other system components.
1256 // No internal state transitions should depend on this variable.
1257 private CallAudioState mCurrentCallAudioState;
Hall Liud109afb2016-01-26 12:53:53 -08001258 private CallAudioState mLastKnownCallAudioState;
Hall Liuf62630a2015-10-27 14:53:39 -07001259
Hall Liu132a5572017-11-02 18:44:57 -07001260 private final boolean mIsInbandRingSupported;
1261
Hall Liuf62630a2015-10-27 14:53:39 -07001262 public CallAudioRouteStateMachine(
1263 Context context,
1264 CallsManager callsManager,
Hall Liu486cb192016-10-21 18:23:33 -07001265 BluetoothRouteManager bluetoothManager,
Hall Liuf62630a2015-10-27 14:53:39 -07001266 WiredHeadsetManager wiredHeadsetManager,
1267 StatusBarNotifier statusBarNotifier,
Hall Liua3e9dda2015-12-15 17:52:50 -08001268 CallAudioManager.AudioServiceFactory audioServiceFactory,
Scott Randolph8aba9d62017-11-01 18:34:19 -07001269 int earpieceControl) {
Hall Liuf62630a2015-10-27 14:53:39 -07001270 super(NAME);
1271 addState(mActiveEarpieceRoute);
1272 addState(mActiveHeadsetRoute);
1273 addState(mActiveBluetoothRoute);
1274 addState(mActiveSpeakerRoute);
Hall Liue271f222016-08-15 18:04:06 -07001275 addState(mRingingBluetoothRoute);
Hall Liuf62630a2015-10-27 14:53:39 -07001276 addState(mQuiescentEarpieceRoute);
1277 addState(mQuiescentHeadsetRoute);
1278 addState(mQuiescentBluetoothRoute);
1279 addState(mQuiescentSpeakerRoute);
1280
1281 mContext = context;
1282 mCallsManager = callsManager;
1283 mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
Hall Liu486cb192016-10-21 18:23:33 -07001284 mBluetoothRouteManager = bluetoothManager;
Hall Liuf62630a2015-10-27 14:53:39 -07001285 mWiredHeadsetManager = wiredHeadsetManager;
1286 mStatusBarNotifier = statusBarNotifier;
1287 mAudioServiceFactory = audioServiceFactory;
Scott Randolph8aba9d62017-11-01 18:34:19 -07001288 switch (earpieceControl) {
1289 case EARPIECE_FORCE_DISABLED:
1290 mDoesDeviceSupportEarpieceRoute = false;
1291 break;
1292 case EARPIECE_FORCE_ENABLED:
1293 mDoesDeviceSupportEarpieceRoute = true;
1294 break;
1295 default:
1296 mDoesDeviceSupportEarpieceRoute = checkForEarpieceSupport();
1297 }
Hall Liu132a5572017-11-02 18:44:57 -07001298 mIsInbandRingSupported = BluetoothHeadset.isInbandRingingSupported(mContext);
Hall Liu609992b2016-08-31 15:48:51 -07001299 mLock = callsManager.getLock();
Hall Liuf62630a2015-10-27 14:53:39 -07001300
1301 mStateNameToRouteCode = new HashMap<>(8);
1302 mStateNameToRouteCode.put(mQuiescentEarpieceRoute.getName(), ROUTE_EARPIECE);
1303 mStateNameToRouteCode.put(mQuiescentBluetoothRoute.getName(), ROUTE_BLUETOOTH);
1304 mStateNameToRouteCode.put(mQuiescentHeadsetRoute.getName(), ROUTE_WIRED_HEADSET);
1305 mStateNameToRouteCode.put(mQuiescentSpeakerRoute.getName(), ROUTE_SPEAKER);
Hall Liue271f222016-08-15 18:04:06 -07001306 mStateNameToRouteCode.put(mRingingBluetoothRoute.getName(), ROUTE_BLUETOOTH);
Hall Liuf62630a2015-10-27 14:53:39 -07001307 mStateNameToRouteCode.put(mActiveEarpieceRoute.getName(), ROUTE_EARPIECE);
1308 mStateNameToRouteCode.put(mActiveBluetoothRoute.getName(), ROUTE_BLUETOOTH);
1309 mStateNameToRouteCode.put(mActiveHeadsetRoute.getName(), ROUTE_WIRED_HEADSET);
1310 mStateNameToRouteCode.put(mActiveSpeakerRoute.getName(), ROUTE_SPEAKER);
1311
1312 mRouteCodeToQuiescentState = new HashMap<>(4);
1313 mRouteCodeToQuiescentState.put(ROUTE_EARPIECE, mQuiescentEarpieceRoute);
1314 mRouteCodeToQuiescentState.put(ROUTE_BLUETOOTH, mQuiescentBluetoothRoute);
1315 mRouteCodeToQuiescentState.put(ROUTE_SPEAKER, mQuiescentSpeakerRoute);
1316 mRouteCodeToQuiescentState.put(ROUTE_WIRED_HEADSET, mQuiescentHeadsetRoute);
Hall Liuf62630a2015-10-27 14:53:39 -07001317 }
1318
1319 /**
1320 * Initializes the state machine with info on initial audio route, supported audio routes,
1321 * and mute status.
1322 */
1323 public void initialize() {
1324 CallAudioState initState = getInitialAudioState();
1325 initialize(initState);
1326 }
1327
1328 public void initialize(CallAudioState initState) {
Christine Hallstrom96a0be62016-11-30 16:05:13 -08001329 if ((initState.getRoute() & getCurrentCallSupportedRoutes()) == 0) {
Hall Liucff959e2016-12-07 14:04:57 -08001330 Log.e(this, new IllegalArgumentException(), "Route %d specified when supported call" +
1331 " routes are: %d", initState.getRoute(), getCurrentCallSupportedRoutes());
Christine Hallstrom96a0be62016-11-30 16:05:13 -08001332 }
1333
Hall Liuf62630a2015-10-27 14:53:39 -07001334 mCurrentCallAudioState = initState;
Hall Liud109afb2016-01-26 12:53:53 -08001335 mLastKnownCallAudioState = initState;
Christine Hallstrom96a0be62016-11-30 16:05:13 -08001336 mDeviceSupportedRoutes = initState.getSupportedRouteMask();
Hall Liucff959e2016-12-07 14:04:57 -08001337 mAvailableRoutes = mDeviceSupportedRoutes & getCurrentCallSupportedRoutes();
Hall Liuf62630a2015-10-27 14:53:39 -07001338 mIsMuted = initState.isMuted();
Hall Liud8ca5452016-03-10 14:53:15 -08001339 mWasOnSpeaker = false;
Hall Liuf62630a2015-10-27 14:53:39 -07001340
1341 mStatusBarNotifier.notifyMute(initState.isMuted());
1342 mStatusBarNotifier.notifySpeakerphone(initState.getRoute() == CallAudioState.ROUTE_SPEAKER);
1343 setInitialState(mRouteCodeToQuiescentState.get(initState.getRoute()));
1344 start();
1345 }
1346
1347 /**
1348 * Getter for the current CallAudioState object that the state machine is keeping track of.
1349 * Used for compatibility purposes.
1350 */
1351 public CallAudioState getCurrentCallAudioState() {
1352 return mCurrentCallAudioState;
1353 }
1354
Brad Ebinger72930a82015-11-23 10:06:40 -08001355 public void sendMessageWithSessionInfo(int message, int arg) {
Hall Liu9086fb12017-11-07 18:01:53 -08001356 sendMessageWithSessionInfo(message, arg, null);
Brad Ebinger72930a82015-11-23 10:06:40 -08001357 }
1358
1359 public void sendMessageWithSessionInfo(int message) {
Hall Liu9086fb12017-11-07 18:01:53 -08001360 sendMessageWithSessionInfo(message, 0, null);
1361 }
1362
1363 public void sendMessageWithSessionInfo(int message, int arg, String data) {
1364 SomeArgs args = SomeArgs.obtain();
1365 args.arg1 = Log.createSubsession();
1366 args.arg2 = data;
1367 sendMessage(message, arg, 0, args);
Brad Ebinger72930a82015-11-23 10:06:40 -08001368 }
1369
Hall Liuf62630a2015-10-27 14:53:39 -07001370 /**
Hall Liu29855702015-12-11 17:42:03 -08001371 * This is for state-independent changes in audio route (i.e. muting or runnables)
Hall Liuf62630a2015-10-27 14:53:39 -07001372 * @param msg that couldn't be handled.
1373 */
1374 @Override
1375 protected void unhandledMessage(Message msg) {
1376 CallAudioState newCallAudioState;
1377 switch (msg.what) {
1378 case MUTE_ON:
1379 setMuteOn(true);
1380 newCallAudioState = new CallAudioState(mIsMuted,
1381 mCurrentCallAudioState.getRoute(),
Hall Liu9086fb12017-11-07 18:01:53 -08001382 mAvailableRoutes,
1383 mCurrentCallAudioState.getActiveBluetoothDevice(),
1384 mBluetoothRouteManager.getConnectedDevices());
Hall Liud109afb2016-01-26 12:53:53 -08001385 setSystemAudioState(newCallAudioState);
Hall Liuf62630a2015-10-27 14:53:39 -07001386 updateInternalCallAudioState();
1387 return;
1388 case MUTE_OFF:
1389 setMuteOn(false);
1390 newCallAudioState = new CallAudioState(mIsMuted,
1391 mCurrentCallAudioState.getRoute(),
Hall Liu9086fb12017-11-07 18:01:53 -08001392 mAvailableRoutes,
1393 mCurrentCallAudioState.getActiveBluetoothDevice(),
1394 mBluetoothRouteManager.getConnectedDevices());
Hall Liud109afb2016-01-26 12:53:53 -08001395 setSystemAudioState(newCallAudioState);
Hall Liuf62630a2015-10-27 14:53:39 -07001396 updateInternalCallAudioState();
1397 return;
1398 case TOGGLE_MUTE:
1399 if (mIsMuted) {
1400 sendInternalMessage(MUTE_OFF);
1401 } else {
1402 sendInternalMessage(MUTE_ON);
1403 }
1404 return;
Hall Liu8c7e2562016-04-13 18:26:03 -07001405 case UPDATE_SYSTEM_AUDIO_ROUTE:
Christine Hallstrom96a0be62016-11-30 16:05:13 -08001406 updateRouteForForegroundCall();
Hall Liu8c7e2562016-04-13 18:26:03 -07001407 resendSystemAudioState();
1408 return;
Hall Liu29855702015-12-11 17:42:03 -08001409 case RUN_RUNNABLE:
Brad Ebingere62e9e82016-02-01 18:26:40 -08001410 java.lang.Runnable r = (java.lang.Runnable) msg.obj;
Hall Liu29855702015-12-11 17:42:03 -08001411 r.run();
1412 return;
Hall Liuf62630a2015-10-27 14:53:39 -07001413 default:
Hall Liu132a5572017-11-02 18:44:57 -07001414 Log.e(this, new IllegalStateException(), "Unexpected message code %d", msg.what);
Hall Liuf62630a2015-10-27 14:53:39 -07001415 }
1416 }
1417
Hall Liu29855702015-12-11 17:42:03 -08001418 public void quitStateMachine() {
1419 quitNow();
1420 }
1421
Hall Liua51c99f2017-03-13 16:39:26 -07001422 public void dumpPendingMessages(IndentingPrintWriter pw) {
1423 getHandler().getLooper().dump(pw::println, "");
1424 }
1425
Hall Liu136f4c92017-04-04 13:35:18 -07001426 public boolean isHfpDeviceAvailable() {
1427 return mBluetoothRouteManager.isBluetoothAvailable();
1428 }
1429
Hall Liuf62630a2015-10-27 14:53:39 -07001430 private void setSpeakerphoneOn(boolean on) {
1431 if (mAudioManager.isSpeakerphoneOn() != on) {
1432 Log.i(this, "turning speaker phone %s", on);
1433 mAudioManager.setSpeakerphoneOn(on);
Hall Liu1d025d02016-06-24 14:01:19 -07001434 mStatusBarNotifier.notifySpeakerphone(on);
Hall Liuf62630a2015-10-27 14:53:39 -07001435 }
1436 }
1437
Hall Liu9086fb12017-11-07 18:01:53 -08001438 private void setBluetoothOn(String address) {
Hall Liu486cb192016-10-21 18:23:33 -07001439 if (mBluetoothRouteManager.isBluetoothAvailable()) {
Hall Liu9086fb12017-11-07 18:01:53 -08001440 BluetoothDevice connectedDevice =
1441 mBluetoothRouteManager.getBluetoothAudioConnectedDevice();
1442 if (address == null && connectedDevice != null) {
1443 // null means connect to any device, so don't bother reconnecting
1444 return;
1445 }
1446 if (connectedDevice == null || !Objects.equals(address, connectedDevice.getAddress())) {
1447 Log.i(this, "connecting bluetooth audio: %s", address);
1448 mBluetoothRouteManager.connectBluetoothAudio(address);
Hall Liu132a5572017-11-02 18:44:57 -07001449 }
1450 }
1451 }
1452
1453 private void setBluetoothOff() {
1454 if (mBluetoothRouteManager.isBluetoothAvailable()) {
1455 if (mBluetoothRouteManager.isBluetoothAudioConnectedOrPending()) {
1456 Log.i(this, "disconnecting bluetooth audio");
1457 mBluetoothRouteManager.disconnectBluetoothAudio();
Hall Liuf62630a2015-10-27 14:53:39 -07001458 }
1459 }
1460 }
1461
1462 private void setMuteOn(boolean mute) {
1463 mIsMuted = mute;
Brad Ebingera3eccfe2016-10-05 15:45:22 -07001464 Log.addEvent(mCallsManager.getForegroundCall(), mute ?
1465 LogUtils.Events.MUTE : LogUtils.Events.UNMUTE);
Hall Liuf62630a2015-10-27 14:53:39 -07001466 if (mute != mAudioManager.isMicrophoneMute() && isInActiveState()) {
1467 IAudioService audio = mAudioServiceFactory.getAudioService();
1468 Log.i(this, "changing microphone mute state to: %b [serviceIsNull=%b]",
1469 mute, audio == null);
1470 if (audio != null) {
1471 try {
1472 // We use the audio service directly here so that we can specify
1473 // the current user. Telecom runs in the system_server process which
1474 // may run as a separate user from the foreground user. If we
1475 // used AudioManager directly, we would change mute for the system's
1476 // user and not the current foreground, which we want to avoid.
1477 audio.setMicrophoneMute(
1478 mute, mContext.getOpPackageName(), getCurrentUserId());
Hall Liu1d025d02016-06-24 14:01:19 -07001479 mStatusBarNotifier.notifyMute(mute);
Hall Liuf62630a2015-10-27 14:53:39 -07001480 } catch (RemoteException e) {
1481 Log.e(this, e, "Remote exception while toggling mute.");
1482 }
1483 // TODO: Check microphone state after attempting to set to ensure that
1484 // our state corroborates AudioManager's state.
1485 }
1486 }
1487 }
1488
1489 /**
1490 * Updates the CallAudioState object from current internal state. The result is used for
1491 * external communication only.
1492 */
1493 private void updateInternalCallAudioState() {
1494 IState currentState = getCurrentState();
1495 if (currentState == null) {
1496 Log.e(this, new IllegalStateException(), "Current state should never be null" +
1497 " when updateInternalCallAudioState is called.");
1498 mCurrentCallAudioState = new CallAudioState(
Hall Liu9086fb12017-11-07 18:01:53 -08001499 mIsMuted, mCurrentCallAudioState.getRoute(), mAvailableRoutes,
1500 mBluetoothRouteManager.getBluetoothAudioConnectedDevice(),
1501 mBluetoothRouteManager.getConnectedDevices());
Hall Liuf62630a2015-10-27 14:53:39 -07001502 return;
1503 }
1504 int currentRoute = mStateNameToRouteCode.get(currentState.getName());
Hall Liu9086fb12017-11-07 18:01:53 -08001505 mCurrentCallAudioState = new CallAudioState(mIsMuted, currentRoute, mAvailableRoutes,
1506 mBluetoothRouteManager.getBluetoothAudioConnectedDevice(),
1507 mBluetoothRouteManager.getConnectedDevices());
Hall Liuf62630a2015-10-27 14:53:39 -07001508 }
1509
Hall Liud109afb2016-01-26 12:53:53 -08001510 private void setSystemAudioState(CallAudioState newCallAudioState) {
Hall Liu8c7e2562016-04-13 18:26:03 -07001511 setSystemAudioState(newCallAudioState, false);
1512 }
1513
1514 private void resendSystemAudioState() {
1515 setSystemAudioState(mLastKnownCallAudioState, true);
1516 }
1517
1518 private void setSystemAudioState(CallAudioState newCallAudioState, boolean force) {
Hall Liu609992b2016-08-31 15:48:51 -07001519 synchronized (mLock) {
1520 Log.i(this, "setSystemAudioState: changing from %s to %s", mLastKnownCallAudioState,
1521 newCallAudioState);
1522 if (force || !newCallAudioState.equals(mLastKnownCallAudioState)) {
Hall Liu874c0f82016-04-29 18:13:18 -07001523
Hall Liu609992b2016-08-31 15:48:51 -07001524 mCallsManager.onCallAudioStateChanged(mLastKnownCallAudioState, newCallAudioState);
1525 updateAudioForForegroundCall(newCallAudioState);
1526 mLastKnownCallAudioState = newCallAudioState;
1527 }
Hall Liuf62630a2015-10-27 14:53:39 -07001528 }
1529 }
1530
1531 private void updateAudioForForegroundCall(CallAudioState newCallAudioState) {
1532 Call call = mCallsManager.getForegroundCall();
1533 if (call != null && call.getConnectionService() != null) {
1534 call.getConnectionService().onCallAudioStateChanged(call, newCallAudioState);
1535 }
1536 }
1537
1538 private int calculateSupportedRoutes() {
1539 int routeMask = CallAudioState.ROUTE_SPEAKER;
1540
1541 if (mWiredHeadsetManager.isPluggedIn()) {
1542 routeMask |= CallAudioState.ROUTE_WIRED_HEADSET;
Hall Liua3e9dda2015-12-15 17:52:50 -08001543 } else if (mDoesDeviceSupportEarpieceRoute){
Hall Liuf62630a2015-10-27 14:53:39 -07001544 routeMask |= CallAudioState.ROUTE_EARPIECE;
1545 }
1546
Hall Liu486cb192016-10-21 18:23:33 -07001547 if (mBluetoothRouteManager.isBluetoothAvailable()) {
Hall Liuf62630a2015-10-27 14:53:39 -07001548 routeMask |= CallAudioState.ROUTE_BLUETOOTH;
1549 }
1550
1551 return routeMask;
1552 }
1553
1554 private void sendInternalMessage(int messageCode) {
Hall Liu95f2db92017-06-19 18:32:55 -07001555 sendInternalMessage(messageCode, 0);
1556 }
1557
1558 private void sendInternalMessage(int messageCode, int arg1) {
Hall Liuf62630a2015-10-27 14:53:39 -07001559 // Internal messages are messages which the state machine sends to itself in the
1560 // course of processing externally-sourced messages. We want to send these messages at
1561 // the front of the queue in order to make actions appear atomic to the user and to
1562 // prevent scenarios such as these:
1563 // 1. State machine handler thread is suspended for some reason.
1564 // 2. Headset gets connected (sends CONNECT_HEADSET).
1565 // 3. User switches to speakerphone in the UI (sends SWITCH_SPEAKER).
1566 // 4. State machine handler is un-suspended.
1567 // 5. State machine handler processes the CONNECT_HEADSET message and sends
1568 // SWITCH_HEADSET at end of queue.
1569 // 6. State machine handler processes SWITCH_SPEAKER.
1570 // 7. State machine handler processes SWITCH_HEADSET.
Brad Ebinger72930a82015-11-23 10:06:40 -08001571 Session subsession = Log.createSubsession();
1572 if(subsession != null) {
Hall Liu9086fb12017-11-07 18:01:53 -08001573 SomeArgs args = SomeArgs.obtain();
1574 args.arg1 = subsession;
1575 sendMessageAtFrontOfQueue(messageCode, arg1, 0, args);
Brad Ebinger72930a82015-11-23 10:06:40 -08001576 } else {
Hall Liu95f2db92017-06-19 18:32:55 -07001577 sendMessageAtFrontOfQueue(messageCode, arg1);
Brad Ebinger72930a82015-11-23 10:06:40 -08001578 }
Hall Liuf62630a2015-10-27 14:53:39 -07001579 }
1580
1581 private CallAudioState getInitialAudioState() {
Christine Hallstrom96a0be62016-11-30 16:05:13 -08001582 int supportedRouteMask = calculateSupportedRoutes() & getCurrentCallSupportedRoutes();
Hall Liua3e9dda2015-12-15 17:52:50 -08001583 final int route;
1584
Hall Liuf62630a2015-10-27 14:53:39 -07001585 if ((supportedRouteMask & ROUTE_BLUETOOTH) != 0) {
1586 route = ROUTE_BLUETOOTH;
Hall Liua3e9dda2015-12-15 17:52:50 -08001587 } else if ((supportedRouteMask & ROUTE_WIRED_HEADSET) != 0) {
1588 route = ROUTE_WIRED_HEADSET;
1589 } else if ((supportedRouteMask & ROUTE_EARPIECE) != 0) {
1590 route = ROUTE_EARPIECE;
1591 } else {
1592 route = ROUTE_SPEAKER;
Hall Liuf62630a2015-10-27 14:53:39 -07001593 }
1594
Hall Liu9086fb12017-11-07 18:01:53 -08001595 return new CallAudioState(false, route, supportedRouteMask, null,
1596 mBluetoothRouteManager.getConnectedDevices());
Hall Liuf62630a2015-10-27 14:53:39 -07001597 }
1598
1599 private int getCurrentUserId() {
1600 final long ident = Binder.clearCallingIdentity();
1601 try {
Sudheer Shanka873dc732016-11-10 16:37:28 -08001602 UserInfo currentUser = ActivityManager.getService().getCurrentUser();
Hall Liuf62630a2015-10-27 14:53:39 -07001603 return currentUser.id;
1604 } catch (RemoteException e) {
1605 // Activity manager not running, nothing we can do assume user 0.
1606 } finally {
1607 Binder.restoreCallingIdentity(ident);
1608 }
1609 return UserHandle.USER_OWNER;
1610 }
1611
1612 private boolean isInActiveState() {
1613 AudioState currentState = (AudioState) getCurrentState();
1614 if (currentState == null) {
1615 Log.w(this, "Current state is null, assuming inactive state");
1616 return false;
1617 }
1618 return currentState.isActive();
1619 }
Hall Liua3e9dda2015-12-15 17:52:50 -08001620
Scott Randolph8aba9d62017-11-01 18:34:19 -07001621 private boolean checkForEarpieceSupport() {
1622 AudioDeviceInfo[] deviceList = mAudioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS);
1623 for (AudioDeviceInfo device: deviceList) {
1624 if (device.getType() == AudioDeviceInfo.TYPE_BUILTIN_EARPIECE) {
1625 return true;
Hall Liua3e9dda2015-12-15 17:52:50 -08001626 }
1627 }
Scott Randolph8aba9d62017-11-01 18:34:19 -07001628 // No earpiece found
1629 return false;
Hall Liua3e9dda2015-12-15 17:52:50 -08001630 }
Hall Liu4f296ba2016-02-18 14:46:57 -08001631
Hall Liu95f2db92017-06-19 18:32:55 -07001632 private int calculateBaselineRouteMessage(boolean isExplicitUserRequest,
1633 boolean includeBluetooth) {
Toshiya Ikenagadb10aec2017-02-16 18:50:33 +08001634 boolean isSkipEarpiece = false;
1635 if (!isExplicitUserRequest) {
1636 synchronized (mLock) {
1637 // Check video calls to skip earpiece since the baseline for video
1638 // calls should be the speakerphone route
1639 isSkipEarpiece = mCallsManager.hasVideoCall();
1640 }
1641 }
Hall Liu95f2db92017-06-19 18:32:55 -07001642 if ((mAvailableRoutes & ROUTE_BLUETOOTH) != 0
1643 && !mHasUserExplicitlyLeftBluetooth
1644 && includeBluetooth) {
1645 return isExplicitUserRequest ? USER_SWITCH_BLUETOOTH : SWITCH_BLUETOOTH;
1646 } else if ((mAvailableRoutes & ROUTE_EARPIECE) != 0 && !isSkipEarpiece) {
Hall Liu4f296ba2016-02-18 14:46:57 -08001647 return isExplicitUserRequest ? USER_SWITCH_EARPIECE : SWITCH_EARPIECE;
1648 } else if ((mAvailableRoutes & ROUTE_WIRED_HEADSET) != 0) {
1649 return isExplicitUserRequest ? USER_SWITCH_HEADSET : SWITCH_HEADSET;
Hall Liu4f296ba2016-02-18 14:46:57 -08001650 } else {
Hall Liucff959e2016-12-07 14:04:57 -08001651 return isExplicitUserRequest ? USER_SWITCH_SPEAKER : SWITCH_SPEAKER;
Hall Liu4f296ba2016-02-18 14:46:57 -08001652 }
1653 }
Hall Liud8ca5452016-03-10 14:53:15 -08001654
1655 private void reinitialize() {
1656 CallAudioState initState = getInitialAudioState();
Christine Hallstrom96a0be62016-11-30 16:05:13 -08001657 mDeviceSupportedRoutes = initState.getSupportedRouteMask();
1658 mAvailableRoutes = mDeviceSupportedRoutes & getCurrentCallSupportedRoutes();
Hall Liud8ca5452016-03-10 14:53:15 -08001659 mIsMuted = initState.isMuted();
1660 setMuteOn(mIsMuted);
1661 mWasOnSpeaker = false;
1662 mHasUserExplicitlyLeftBluetooth = false;
Garik Badalyanb3cbeb02016-05-06 17:04:24 -07001663 mLastKnownCallAudioState = initState;
Hall Liud8ca5452016-03-10 14:53:15 -08001664 transitionTo(mRouteCodeToQuiescentState.get(initState.getRoute()));
1665 }
Christine Hallstrom96a0be62016-11-30 16:05:13 -08001666
1667 private void updateRouteForForegroundCall() {
1668 mAvailableRoutes = mDeviceSupportedRoutes & getCurrentCallSupportedRoutes();
1669
1670 CallAudioState currentState = getCurrentCallAudioState();
1671
1672 // Move to baseline route in the case the current route is no longer available.
1673 if ((mAvailableRoutes & currentState.getRoute()) == 0) {
Hall Liu95f2db92017-06-19 18:32:55 -07001674 sendInternalMessage(calculateBaselineRouteMessage(false, true));
Christine Hallstrom96a0be62016-11-30 16:05:13 -08001675 }
1676 }
Hall Liucff959e2016-12-07 14:04:57 -08001677
1678 private int getCurrentCallSupportedRoutes() {
1679 int supportedRoutes = CallAudioState.ROUTE_ALL;
1680
1681 if (mCallsManager.getForegroundCall() != null) {
1682 supportedRoutes &= mCallsManager.getForegroundCall().getSupportedAudioRoutes();
1683 }
1684
1685 return supportedRoutes;
1686 }
1687
1688 private int modifyRoutes(int base, int remove, int add, boolean considerCurrentCall) {
1689 base &= ~remove;
1690
1691 if (considerCurrentCall) {
1692 add &= getCurrentCallSupportedRoutes();
1693 }
1694
1695 base |= add;
1696
1697 return base;
1698 }
Garik Badalyanb3cbeb02016-05-06 17:04:24 -07001699}