1 /* 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 17 package com.android.server.telecom; 18 19 import android.media.AudioAttributes; 20 import android.media.AudioFocusRequest; 21 import android.media.AudioManager; 22 import android.os.Looper; 23 import android.os.Message; 24 import android.os.Trace; 25 import android.telecom.Log; 26 import android.telecom.Logging.Runnable; 27 import android.telecom.Logging.Session; 28 import android.util.LocalLog; 29 import android.util.SparseArray; 30 import com.android.internal.util.IState; 31 import com.android.internal.util.IndentingPrintWriter; 32 import com.android.internal.util.State; 33 import com.android.internal.util.StateMachine; 34 import com.android.server.telecom.flags.FeatureFlags; 35 36 public class CallAudioModeStateMachine extends StateMachine { 37 /** 38 * Captures the most recent CallAudioModeStateMachine state transitions and the corresponding 39 * changes to the {@link AudioManager#setMode}. 40 */ 41 private LocalLog mLocalLog = new LocalLog(20); 42 public static class Factory { create(SystemStateHelper systemStateHelper, AudioManager am, FeatureFlags featureFlags, CallAudioCommunicationDeviceTracker callAudioCommunicationDeviceTracker)43 public CallAudioModeStateMachine create(SystemStateHelper systemStateHelper, 44 AudioManager am, FeatureFlags featureFlags, 45 CallAudioCommunicationDeviceTracker callAudioCommunicationDeviceTracker) { 46 return new CallAudioModeStateMachine(systemStateHelper, am, 47 featureFlags, callAudioCommunicationDeviceTracker); 48 } 49 } 50 51 private static final AudioAttributes RING_AUDIO_ATTRIBUTES = new AudioAttributes.Builder() 52 .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE) 53 .setLegacyStreamType(AudioManager.STREAM_RING) 54 .build(); 55 public static final AudioFocusRequest RING_AUDIO_FOCUS_REQUEST = new AudioFocusRequest 56 .Builder(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT) 57 .setAudioAttributes(RING_AUDIO_ATTRIBUTES).build(); 58 59 private static final AudioAttributes CALL_AUDIO_ATTRIBUTES = new AudioAttributes.Builder() 60 .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION) 61 .setLegacyStreamType(AudioManager.STREAM_VOICE_CALL) 62 .build(); 63 public static final AudioFocusRequest CALL_AUDIO_FOCUS_REQUEST = new AudioFocusRequest 64 .Builder(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT) 65 .setAudioAttributes(CALL_AUDIO_ATTRIBUTES).build(); 66 67 public static class MessageArgs { 68 public boolean hasActiveOrDialingCalls; 69 public boolean hasRingingCalls; 70 public boolean hasHoldingCalls; 71 public boolean hasAudioProcessingCalls; 72 public boolean isTonePlaying; 73 public boolean foregroundCallIsVoip; 74 public boolean isStreaming; 75 public Session session; 76 MessageArgs(boolean hasActiveOrDialingCalls, boolean hasRingingCalls, boolean hasHoldingCalls, boolean hasAudioProcessingCalls, boolean isTonePlaying, boolean foregroundCallIsVoip, boolean isStreaming, Session session)77 private MessageArgs(boolean hasActiveOrDialingCalls, boolean hasRingingCalls, 78 boolean hasHoldingCalls, boolean hasAudioProcessingCalls, boolean isTonePlaying, 79 boolean foregroundCallIsVoip, boolean isStreaming, Session session) { 80 this.hasActiveOrDialingCalls = hasActiveOrDialingCalls; 81 this.hasRingingCalls = hasRingingCalls; 82 this.hasHoldingCalls = hasHoldingCalls; 83 this.hasAudioProcessingCalls = hasAudioProcessingCalls; 84 this.isTonePlaying = isTonePlaying; 85 this.foregroundCallIsVoip = foregroundCallIsVoip; 86 this.isStreaming = isStreaming; 87 this.session = session; 88 } 89 90 @Override toString()91 public String toString() { 92 return "MessageArgs{" + 93 "hasActiveCalls=" + hasActiveOrDialingCalls + 94 ", hasRingingCalls=" + hasRingingCalls + 95 ", hasHoldingCalls=" + hasHoldingCalls + 96 ", hasAudioProcessingCalls=" + hasAudioProcessingCalls + 97 ", isTonePlaying=" + isTonePlaying + 98 ", foregroundCallIsVoip=" + foregroundCallIsVoip + 99 ", isStreaming=" + isStreaming + 100 ", session=" + session + 101 '}'; 102 } 103 104 public static class Builder { 105 private boolean mHasActiveOrDialingCalls; 106 private boolean mHasRingingCalls; 107 private boolean mHasHoldingCalls; 108 private boolean mHasAudioProcessingCalls; 109 private boolean mIsTonePlaying; 110 private boolean mForegroundCallIsVoip; 111 private boolean mIsStreaming; 112 private Session mSession; 113 setHasActiveOrDialingCalls(boolean hasActiveOrDialingCalls)114 public Builder setHasActiveOrDialingCalls(boolean hasActiveOrDialingCalls) { 115 mHasActiveOrDialingCalls = hasActiveOrDialingCalls; 116 return this; 117 } 118 setHasRingingCalls(boolean hasRingingCalls)119 public Builder setHasRingingCalls(boolean hasRingingCalls) { 120 mHasRingingCalls = hasRingingCalls; 121 return this; 122 } 123 setHasHoldingCalls(boolean hasHoldingCalls)124 public Builder setHasHoldingCalls(boolean hasHoldingCalls) { 125 mHasHoldingCalls = hasHoldingCalls; 126 return this; 127 } 128 setHasAudioProcessingCalls(boolean hasAudioProcessingCalls)129 public Builder setHasAudioProcessingCalls(boolean hasAudioProcessingCalls) { 130 mHasAudioProcessingCalls = hasAudioProcessingCalls; 131 return this; 132 } 133 setIsTonePlaying(boolean isTonePlaying)134 public Builder setIsTonePlaying(boolean isTonePlaying) { 135 mIsTonePlaying = isTonePlaying; 136 return this; 137 } 138 setForegroundCallIsVoip(boolean foregroundCallIsVoip)139 public Builder setForegroundCallIsVoip(boolean foregroundCallIsVoip) { 140 mForegroundCallIsVoip = foregroundCallIsVoip; 141 return this; 142 } 143 setSession(Session session)144 public Builder setSession(Session session) { 145 mSession = session; 146 return this; 147 } 148 setIsStreaming(boolean isStraeming)149 public Builder setIsStreaming(boolean isStraeming) { 150 mIsStreaming = isStraeming; 151 return this; 152 } 153 build()154 public MessageArgs build() { 155 return new MessageArgs(mHasActiveOrDialingCalls, mHasRingingCalls, mHasHoldingCalls, 156 mHasAudioProcessingCalls, mIsTonePlaying, mForegroundCallIsVoip, 157 mIsStreaming, mSession); 158 } 159 } 160 } 161 162 // TODO: remove this and replace when the new audio mode gets pushed to AOSP. 163 public static final int NEW_AUDIO_MODE_FOR_AUDIO_PROCESSING = 4; 164 165 public static final int INITIALIZE = 1; 166 // These ENTER_*_FOCUS commands are for testing. 167 public static final int ENTER_CALL_FOCUS_FOR_TESTING = 2; 168 public static final int ENTER_COMMS_FOCUS_FOR_TESTING = 3; 169 public static final int ENTER_RING_FOCUS_FOR_TESTING = 4; 170 public static final int ENTER_TONE_OR_HOLD_FOCUS_FOR_TESTING = 5; 171 public static final int ENTER_AUDIO_PROCESSING_FOCUS_FOR_TESTING = 6; 172 public static final int ENTER_STREAMING_FOCUS_FOR_TESTING = 7; 173 public static final int ABANDON_FOCUS_FOR_TESTING = 8; 174 175 public static final int NO_MORE_ACTIVE_OR_DIALING_CALLS = 1001; 176 public static final int NO_MORE_RINGING_CALLS = 1002; 177 public static final int NO_MORE_HOLDING_CALLS = 1003; 178 public static final int NO_MORE_AUDIO_PROCESSING_CALLS = 1004; 179 180 public static final int NEW_ACTIVE_OR_DIALING_CALL = 2001; 181 public static final int NEW_RINGING_CALL = 2002; 182 public static final int NEW_HOLDING_CALL = 2003; 183 public static final int NEW_AUDIO_PROCESSING_CALL = 2004; 184 185 public static final int TONE_STARTED_PLAYING = 3001; 186 public static final int TONE_STOPPED_PLAYING = 3002; 187 188 public static final int FOREGROUND_VOIP_MODE_CHANGE = 4001; 189 190 public static final int RINGER_MODE_CHANGE = 5001; 191 192 // Used to indicate that Telecom is done doing things to the AudioManager and that it's safe 193 // to release focus for other apps to take over. 194 public static final int AUDIO_OPERATIONS_COMPLETE = 6001; 195 196 public static final int START_CALL_STREAMING = 7001; 197 public static final int STOP_CALL_STREAMING = 7002; 198 199 public static final int RUN_RUNNABLE = 9001; 200 201 private static final SparseArray<String> MESSAGE_CODE_TO_NAME = new SparseArray<String>() {{ 202 put(ENTER_CALL_FOCUS_FOR_TESTING, "ENTER_CALL_FOCUS_FOR_TESTING"); 203 put(ENTER_COMMS_FOCUS_FOR_TESTING, "ENTER_COMMS_FOCUS_FOR_TESTING"); 204 put(ENTER_RING_FOCUS_FOR_TESTING, "ENTER_RING_FOCUS_FOR_TESTING"); 205 put(ENTER_AUDIO_PROCESSING_FOCUS_FOR_TESTING, "ENTER_AUDIO_PROCESSING_FOCUS_FOR_TESTING"); 206 put(ENTER_TONE_OR_HOLD_FOCUS_FOR_TESTING, "ENTER_TONE_OR_HOLD_FOCUS_FOR_TESTING"); 207 put(ABANDON_FOCUS_FOR_TESTING, "ABANDON_FOCUS_FOR_TESTING"); 208 put(NO_MORE_ACTIVE_OR_DIALING_CALLS, "NO_MORE_ACTIVE_OR_DIALING_CALLS"); 209 put(NO_MORE_RINGING_CALLS, "NO_MORE_RINGING_CALLS"); 210 put(NO_MORE_HOLDING_CALLS, "NO_MORE_HOLDING_CALLS"); 211 put(NO_MORE_AUDIO_PROCESSING_CALLS, "NO_MORE_AUDIO_PROCESSING_CALLS"); 212 put(NEW_ACTIVE_OR_DIALING_CALL, "NEW_ACTIVE_OR_DIALING_CALL"); 213 put(NEW_RINGING_CALL, "NEW_RINGING_CALL"); 214 put(NEW_HOLDING_CALL, "NEW_HOLDING_CALL"); 215 put(NEW_AUDIO_PROCESSING_CALL, "NEW_AUDIO_PROCESSING_CALL"); 216 put(TONE_STARTED_PLAYING, "TONE_STARTED_PLAYING"); 217 put(TONE_STOPPED_PLAYING, "TONE_STOPPED_PLAYING"); 218 put(FOREGROUND_VOIP_MODE_CHANGE, "FOREGROUND_VOIP_MODE_CHANGE"); 219 put(RINGER_MODE_CHANGE, "RINGER_MODE_CHANGE"); 220 put(AUDIO_OPERATIONS_COMPLETE, "AUDIO_OPERATIONS_COMPLETE"); 221 put(START_CALL_STREAMING, "START_CALL_STREAMING"); 222 put(STOP_CALL_STREAMING, "STOP_CALL_STREAMING"); 223 224 put(RUN_RUNNABLE, "RUN_RUNNABLE"); 225 }}; 226 227 public static final String TONE_HOLD_STATE_NAME = OtherFocusState.class.getSimpleName(); 228 public static final String UNFOCUSED_STATE_NAME = UnfocusedState.class.getSimpleName(); 229 public static final String AUDIO_PROCESSING_STATE_NAME = 230 AudioProcessingFocusState.class.getSimpleName(); 231 public static final String CALL_STATE_NAME = SimCallFocusState.class.getSimpleName(); 232 public static final String RING_STATE_NAME = RingingFocusState.class.getSimpleName(); 233 public static final String STREAMING_STATE_NAME = StreamingFocusState.class.getSimpleName(); 234 public static final String COMMS_STATE_NAME = VoipCallFocusState.class.getSimpleName(); 235 236 private AudioFocusRequest mCurrentAudioFocusRequest = null; 237 238 private class BaseState extends State { 239 @Override processMessage(Message msg)240 public boolean processMessage(Message msg) { 241 switch (msg.what) { 242 case ENTER_CALL_FOCUS_FOR_TESTING: 243 transitionTo(mSimCallFocusState); 244 return HANDLED; 245 case ENTER_COMMS_FOCUS_FOR_TESTING: 246 transitionTo(mVoipCallFocusState); 247 return HANDLED; 248 case ENTER_RING_FOCUS_FOR_TESTING: 249 transitionTo(mRingingFocusState); 250 return HANDLED; 251 case ENTER_TONE_OR_HOLD_FOCUS_FOR_TESTING: 252 transitionTo(mOtherFocusState); 253 return HANDLED; 254 case ENTER_AUDIO_PROCESSING_FOCUS_FOR_TESTING: 255 transitionTo(mAudioProcessingFocusState); 256 return HANDLED; 257 case ENTER_STREAMING_FOCUS_FOR_TESTING: 258 transitionTo(mStreamingFocusState); 259 return HANDLED; 260 case ABANDON_FOCUS_FOR_TESTING: 261 transitionTo(mUnfocusedState); 262 return HANDLED; 263 case INITIALIZE: 264 mIsInitialized = true; 265 return HANDLED; 266 case RUN_RUNNABLE: 267 java.lang.Runnable r = (java.lang.Runnable) msg.obj; 268 r.run(); 269 return HANDLED; 270 default: 271 return NOT_HANDLED; 272 } 273 } 274 } 275 276 private class UnfocusedState extends BaseState { 277 @Override enter()278 public void enter() { 279 Log.i(LOG_TAG, "Audio focus entering UNFOCUSED state"); 280 mLocalLog.log("Enter UNFOCUSED"); 281 if (mIsInitialized) { 282 // Clear any communication device that was requested previously. 283 // Todo: Remove once clearCommunicationDeviceAfterAudioOpsComplete is 284 // completely rolled out. 285 if (mFeatureFlags.callAudioCommunicationDeviceRefactor() 286 && !mFeatureFlags.clearCommunicationDeviceAfterAudioOpsComplete()) { 287 mCommunicationDeviceTracker.clearCommunicationDevice(mCommunicationDeviceTracker 288 .getCurrentLocallyRequestedCommunicationDevice()); 289 } 290 if (mFeatureFlags.setAudioModeBeforeAbandonFocus()) { 291 mAudioManager.setMode(AudioManager.MODE_NORMAL); 292 mCallAudioManager.setCallAudioRouteFocusState( 293 CallAudioRouteStateMachine.NO_FOCUS); 294 } else { 295 mCallAudioManager.setCallAudioRouteFocusState( 296 CallAudioRouteStateMachine.NO_FOCUS); 297 mAudioManager.setMode(AudioManager.MODE_NORMAL); 298 } 299 mLocalLog.log("Mode MODE_NORMAL"); 300 mMostRecentMode = AudioManager.MODE_NORMAL; 301 // Don't release focus here -- wait until we get a signal that any other audio 302 // operations triggered by this are done before releasing focus. 303 } 304 } 305 306 @Override processMessage(Message msg)307 public boolean processMessage(Message msg) { 308 if (super.processMessage(msg) == HANDLED) { 309 return HANDLED; 310 } 311 MessageArgs args = (MessageArgs) msg.obj; 312 switch (msg.what) { 313 case NO_MORE_ACTIVE_OR_DIALING_CALLS: 314 // Do nothing. 315 return HANDLED; 316 case NO_MORE_RINGING_CALLS: 317 // Do nothing. 318 return HANDLED; 319 case NO_MORE_HOLDING_CALLS: 320 // Do nothing. 321 return HANDLED; 322 case NO_MORE_AUDIO_PROCESSING_CALLS: 323 // Do nothing. 324 return HANDLED; 325 case NEW_ACTIVE_OR_DIALING_CALL: 326 transitionTo(args.foregroundCallIsVoip 327 ? mVoipCallFocusState : mSimCallFocusState); 328 return HANDLED; 329 case NEW_RINGING_CALL: 330 transitionTo(mRingingFocusState); 331 return HANDLED; 332 case NEW_AUDIO_PROCESSING_CALL: 333 transitionTo(mAudioProcessingFocusState); 334 return HANDLED; 335 case NEW_HOLDING_CALL: 336 // This really shouldn't happen, but transition to the focused state anyway. 337 Log.w(LOG_TAG, "Call was surprisingly put into hold from an unknown state." + 338 " Args are: \n" + args.toString()); 339 transitionTo(mOtherFocusState); 340 return HANDLED; 341 case START_CALL_STREAMING: 342 transitionTo(mStreamingFocusState); 343 return HANDLED; 344 case TONE_STARTED_PLAYING: 345 // This shouldn't happen either, but perform the action anyway. 346 Log.w(LOG_TAG, "Tone started playing unexpectedly. Args are: \n" 347 + args.toString()); 348 return HANDLED; 349 case AUDIO_OPERATIONS_COMPLETE: 350 Log.i(LOG_TAG, "Abandoning audio focus: now UNFOCUSED"); 351 if (mFeatureFlags.telecomResolveHiddenDependencies()) { 352 if (mCurrentAudioFocusRequest != null) { 353 mAudioManager.abandonAudioFocusRequest(mCurrentAudioFocusRequest); 354 mCurrentAudioFocusRequest = null; 355 } 356 } else { 357 mAudioManager.abandonAudioFocusForCall(); 358 } 359 // Clear requested communication device after the call ends. 360 if (mFeatureFlags.clearCommunicationDeviceAfterAudioOpsComplete()) { 361 mCommunicationDeviceTracker.clearCommunicationDevice( 362 mCommunicationDeviceTracker 363 .getCurrentLocallyRequestedCommunicationDevice()); 364 } 365 return HANDLED; 366 default: 367 // The forced focus switch commands are handled by BaseState. 368 return NOT_HANDLED; 369 } 370 } 371 } 372 373 private class AudioProcessingFocusState extends BaseState { 374 @Override enter()375 public void enter() { 376 Log.i(LOG_TAG, "Audio focus entering AUDIO_PROCESSING state"); 377 mLocalLog.log("Enter AUDIO_PROCESSING"); 378 if (mIsInitialized) { 379 mCallAudioManager.setCallAudioRouteFocusState(CallAudioRouteStateMachine.NO_FOCUS); 380 mAudioManager.setMode(NEW_AUDIO_MODE_FOR_AUDIO_PROCESSING); 381 mLocalLog.log("Mode MODE_CALL_SCREENING"); 382 mMostRecentMode = NEW_AUDIO_MODE_FOR_AUDIO_PROCESSING; 383 } 384 } 385 386 @Override processMessage(Message msg)387 public boolean processMessage(Message msg) { 388 if (super.processMessage(msg) == HANDLED) { 389 return HANDLED; 390 } 391 MessageArgs args = (MessageArgs) msg.obj; 392 switch (msg.what) { 393 case NO_MORE_ACTIVE_OR_DIALING_CALLS: 394 // Do nothing. 395 return HANDLED; 396 case NO_MORE_RINGING_CALLS: 397 // Do nothing. 398 return HANDLED; 399 case NO_MORE_HOLDING_CALLS: 400 // Do nothing. 401 return HANDLED; 402 case NO_MORE_AUDIO_PROCESSING_CALLS: 403 BaseState destState = calculateProperStateFromArgs(args); 404 if (destState == this) { 405 Log.w(LOG_TAG, "Got spurious NO_MORE_AUDIO_PROCESSING_CALLS"); 406 } 407 transitionTo(destState); 408 return HANDLED; 409 case NEW_ACTIVE_OR_DIALING_CALL: 410 transitionTo(args.foregroundCallIsVoip 411 ? mVoipCallFocusState : mSimCallFocusState); 412 return HANDLED; 413 case NEW_RINGING_CALL: 414 transitionTo(mRingingFocusState); 415 return HANDLED; 416 case NEW_HOLDING_CALL: 417 // This really shouldn't happen, but recalculate from args and do the transition 418 Log.w(LOG_TAG, "Call was surprisingly put into hold from an unknown state." + 419 " Args are: \n" + args.toString()); 420 transitionTo(mOtherFocusState); 421 return HANDLED; 422 case NEW_AUDIO_PROCESSING_CALL: 423 // Can happen as a duplicate message 424 return HANDLED; 425 case TONE_STARTED_PLAYING: 426 // This shouldn't happen either, but perform the action anyway. 427 Log.w(LOG_TAG, "Tone started playing unexpectedly. Args are: \n" 428 + args.toString()); 429 return HANDLED; 430 case START_CALL_STREAMING: 431 transitionTo(mStreamingFocusState); 432 return HANDLED; 433 case AUDIO_OPERATIONS_COMPLETE: 434 Log.i(LOG_TAG, "Abandoning audio focus: now AUDIO_PROCESSING"); 435 if (mFeatureFlags.telecomResolveHiddenDependencies()) { 436 if (mCurrentAudioFocusRequest != null) { 437 mAudioManager.abandonAudioFocusRequest(mCurrentAudioFocusRequest); 438 mCurrentAudioFocusRequest = null; 439 } 440 } else { 441 mAudioManager.abandonAudioFocusForCall(); 442 } 443 return HANDLED; 444 default: 445 // The forced focus switch commands are handled by BaseState. 446 return NOT_HANDLED; 447 } 448 } 449 } 450 451 private class RingingFocusState extends BaseState { 452 // Keeps track of whether we're ringing with audio focus or if we've just entered the state 453 // without acquiring focus because of a silent ringtone or something. 454 private boolean mHasFocus = false; 455 tryStartRinging()456 private void tryStartRinging() { 457 Trace.traceBegin(Trace.TRACE_TAG_AUDIO, "CallAudioMode.tryStartRinging"); 458 try { 459 if (mHasFocus && mCallAudioManager.isRingtonePlaying()) { 460 Log.i(LOG_TAG, 461 "RingingFocusState#tryStartRinging -- audio focus previously" 462 + " acquired and ringtone already playing -- skipping."); 463 return; 464 } 465 466 if (mCallAudioManager.startRinging()) { 467 if (mFeatureFlags.telecomResolveHiddenDependencies()) { 468 mCurrentAudioFocusRequest = RING_AUDIO_FOCUS_REQUEST; 469 mAudioManager.requestAudioFocus(RING_AUDIO_FOCUS_REQUEST); 470 } else { 471 mAudioManager.requestAudioFocusForCall( 472 AudioManager.STREAM_RING, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT); 473 } 474 // Do not set MODE_RINGTONE if we were previously in the CALL_SCREENING mode -- 475 // this trips up the audio system. 476 if (mAudioManager.getMode() != AudioManager.MODE_CALL_SCREENING) { 477 mAudioManager.setMode(AudioManager.MODE_RINGTONE); 478 mLocalLog.log("Mode MODE_RINGTONE"); 479 } 480 mCallAudioManager.setCallAudioRouteFocusState( 481 CallAudioRouteStateMachine.RINGING_FOCUS); 482 mHasFocus = true; 483 } else { 484 Log.i( 485 LOG_TAG, "RINGING state, try start ringing but not acquiring audio focus"); 486 } 487 } finally { 488 Trace.traceEnd(Trace.TRACE_TAG_AUDIO); 489 } 490 } 491 492 @Override enter()493 public void enter() { 494 Log.i(LOG_TAG, "Audio focus entering RINGING state"); 495 mLocalLog.log("Enter RINGING"); 496 tryStartRinging(); 497 mCallAudioManager.stopCallWaiting(); 498 } 499 500 @Override exit()501 public void exit() { 502 // Audio mode and audio stream will be set by the next state. 503 mCallAudioManager.stopRinging(); 504 mHasFocus = false; 505 } 506 507 @Override processMessage(Message msg)508 public boolean processMessage(Message msg) { 509 if (super.processMessage(msg) == HANDLED) { 510 return HANDLED; 511 } 512 MessageArgs args = (MessageArgs) msg.obj; 513 switch (msg.what) { 514 case NO_MORE_ACTIVE_OR_DIALING_CALLS: 515 // Do nothing. Loss of an active call should not impact ringer. 516 return HANDLED; 517 case NO_MORE_HOLDING_CALLS: 518 // Do nothing and keep ringing. 519 return HANDLED; 520 case NO_MORE_RINGING_CALLS: 521 BaseState destState = calculateProperStateFromArgs(args); 522 if (destState == this) { 523 Log.w(LOG_TAG, "Got spurious NO_MORE_RINGING_CALLS"); 524 } 525 transitionTo(destState); 526 return HANDLED; 527 case NEW_ACTIVE_OR_DIALING_CALL: 528 // If a call becomes active suddenly, give it priority over ringing. 529 transitionTo(args.foregroundCallIsVoip 530 ? mVoipCallFocusState : mSimCallFocusState); 531 return HANDLED; 532 case NEW_AUDIO_PROCESSING_CALL: 533 // If we don't have any more ringing calls, transition to audio processing. 534 if (!args.hasRingingCalls) { 535 transitionTo(mAudioProcessingFocusState); 536 } else { 537 Log.w(LOG_TAG, "Got a audio processing call while there's still a call " 538 + "ringing"); 539 } 540 case NEW_RINGING_CALL: 541 // Can happen as a duplicate message 542 return HANDLED; 543 case NEW_HOLDING_CALL: 544 // This really shouldn't happen, but transition to the focused state anyway. 545 Log.w(LOG_TAG, "Call was surprisingly put into hold while ringing." + 546 " Args are: " + args.toString()); 547 transitionTo(mOtherFocusState); 548 return HANDLED; 549 case RINGER_MODE_CHANGE: { 550 Log.i(LOG_TAG, "RINGING state, received RINGER_MODE_CHANGE"); 551 tryStartRinging(); 552 return HANDLED; 553 } 554 case AUDIO_OPERATIONS_COMPLETE: 555 Log.w(LOG_TAG, "Should not be seeing AUDIO_OPERATIONS_COMPLETE in a focused" 556 + " state"); 557 return HANDLED; 558 default: 559 // The forced focus switch commands are handled by BaseState. 560 return NOT_HANDLED; 561 } 562 } 563 } 564 565 private class SimCallFocusState extends BaseState { 566 @Override enter()567 public void enter() { 568 Log.i(LOG_TAG, "Audio focus entering SIM CALL state"); 569 mLocalLog.log("Enter SIM_CALL"); 570 if (mFeatureFlags.telecomResolveHiddenDependencies()) { 571 mCurrentAudioFocusRequest = CALL_AUDIO_FOCUS_REQUEST; 572 mAudioManager.requestAudioFocus(CALL_AUDIO_FOCUS_REQUEST); 573 } else { 574 mAudioManager.requestAudioFocusForCall(AudioManager.STREAM_VOICE_CALL, 575 AudioManager.AUDIOFOCUS_GAIN_TRANSIENT); 576 } 577 mAudioManager.setMode(AudioManager.MODE_IN_CALL); 578 mLocalLog.log("Mode MODE_IN_CALL"); 579 mMostRecentMode = AudioManager.MODE_IN_CALL; 580 mCallAudioManager.setCallAudioRouteFocusState(CallAudioRouteStateMachine.ACTIVE_FOCUS); 581 } 582 583 @Override processMessage(Message msg)584 public boolean processMessage(Message msg) { 585 if (super.processMessage(msg) == HANDLED) { 586 return HANDLED; 587 } 588 MessageArgs args = (MessageArgs) msg.obj; 589 switch (msg.what) { 590 case NO_MORE_ACTIVE_OR_DIALING_CALLS: 591 // Switch to either ringing, holding, or inactive 592 transitionTo(calculateProperStateFromArgs(args)); 593 return HANDLED; 594 case NO_MORE_RINGING_CALLS: 595 // Don't transition state, but stop any call-waiting tones that may have been 596 // playing. 597 if (args.isTonePlaying) { 598 mCallAudioManager.stopCallWaiting(); 599 } 600 // If a MT-audio-speedup call gets disconnected by the connection service 601 // concurrently with the user answering it, we may get this message 602 // indicating that a ringing call has disconnected while this state machine 603 // is in the SimCallFocusState. 604 if (!args.hasActiveOrDialingCalls) { 605 transitionTo(calculateProperStateFromArgs(args)); 606 } 607 return HANDLED; 608 case NO_MORE_HOLDING_CALLS: 609 if (args.foregroundCallIsVoip) { 610 transitionTo(mVoipCallFocusState); 611 } 612 return HANDLED; 613 case NEW_ACTIVE_OR_DIALING_CALL: 614 if (args.foregroundCallIsVoip) { 615 transitionTo(mVoipCallFocusState); 616 } 617 return HANDLED; 618 case NEW_RINGING_CALL: 619 // Don't make a call ring over an active call, but do play a call waiting tone. 620 mCallAudioManager.startCallWaiting("call already active"); 621 return HANDLED; 622 case NEW_HOLDING_CALL: 623 // Just check the voip mode. Putting an active call on hold will be handled when 624 // NO_MORE_ACTIVE_CALLS is processed. 625 if (args.foregroundCallIsVoip) { 626 transitionTo(mVoipCallFocusState); 627 } 628 return HANDLED; 629 case NEW_AUDIO_PROCESSING_CALL: 630 // If we don't have any more active calls, transition to audio processing. 631 if (!args.hasActiveOrDialingCalls) { 632 transitionTo(mAudioProcessingFocusState); 633 } else { 634 Log.w(LOG_TAG, "Got a audio processing call while there's still a call " 635 + "active"); 636 } 637 case FOREGROUND_VOIP_MODE_CHANGE: 638 if (args.foregroundCallIsVoip) { 639 transitionTo(mVoipCallFocusState); 640 } 641 return HANDLED; 642 case AUDIO_OPERATIONS_COMPLETE: 643 Log.w(LOG_TAG, "Should not be seeing AUDIO_OPERATIONS_COMPLETE in a focused" 644 + " state"); 645 return HANDLED; 646 default: 647 // The forced focus switch commands are handled by BaseState. 648 return NOT_HANDLED; 649 } 650 } 651 } 652 653 private class VoipCallFocusState extends BaseState { 654 @Override enter()655 public void enter() { 656 Log.i(LOG_TAG, "Audio focus entering VOIP CALL state"); 657 mLocalLog.log("Enter VOIP_CALL"); 658 if (mFeatureFlags.telecomResolveHiddenDependencies()) { 659 mCurrentAudioFocusRequest = CALL_AUDIO_FOCUS_REQUEST; 660 mAudioManager.requestAudioFocus(CALL_AUDIO_FOCUS_REQUEST); 661 } else { 662 mAudioManager.requestAudioFocusForCall(AudioManager.STREAM_VOICE_CALL, 663 AudioManager.AUDIOFOCUS_GAIN_TRANSIENT); 664 } 665 mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION); 666 mLocalLog.log("Mode MODE_IN_COMMUNICATION"); 667 mMostRecentMode = AudioManager.MODE_IN_COMMUNICATION; 668 mCallAudioManager.setCallAudioRouteFocusState(CallAudioRouteStateMachine.ACTIVE_FOCUS); 669 } 670 671 @Override processMessage(Message msg)672 public boolean processMessage(Message msg) { 673 if (super.processMessage(msg) == HANDLED) { 674 return HANDLED; 675 } 676 MessageArgs args = (MessageArgs) msg.obj; 677 switch (msg.what) { 678 case NO_MORE_ACTIVE_OR_DIALING_CALLS: 679 // Switch to either ringing, holding, or inactive 680 transitionTo(calculateProperStateFromArgs(args)); 681 return HANDLED; 682 case NO_MORE_RINGING_CALLS: 683 // Don't transition state, but stop any call-waiting tones that may have been 684 // playing. 685 if (args.isTonePlaying) { 686 mCallAudioManager.stopCallWaiting(); 687 } 688 return HANDLED; 689 case NO_MORE_HOLDING_CALLS: 690 if (!args.foregroundCallIsVoip) { 691 transitionTo(mSimCallFocusState); 692 } 693 return HANDLED; 694 case NEW_ACTIVE_OR_DIALING_CALL: 695 if (!args.foregroundCallIsVoip) { 696 transitionTo(mSimCallFocusState); 697 } 698 return HANDLED; 699 case NEW_RINGING_CALL: 700 // Don't make a call ring over an active call, but do play a call waiting tone. 701 mCallAudioManager.startCallWaiting("call already active"); 702 return HANDLED; 703 case NEW_HOLDING_CALL: 704 // Just check the voip mode. Putting an active call on hold will be handled when 705 // NO_MORE_ACTIVE_CALLS is processed. 706 if (!args.foregroundCallIsVoip) { 707 transitionTo(mSimCallFocusState); 708 } 709 return HANDLED; 710 case NEW_AUDIO_PROCESSING_CALL: 711 // If we don't have any more active calls, transition to audio processing. 712 if (!args.hasActiveOrDialingCalls) { 713 transitionTo(mAudioProcessingFocusState); 714 } else { 715 Log.w(LOG_TAG, "Got a audio processing call while there's still a call " 716 + "active"); 717 } 718 case FOREGROUND_VOIP_MODE_CHANGE: 719 if (!args.foregroundCallIsVoip) { 720 transitionTo(mSimCallFocusState); 721 } 722 return HANDLED; 723 case AUDIO_OPERATIONS_COMPLETE: 724 Log.w(LOG_TAG, "Should not be seeing AUDIO_OPERATIONS_COMPLETE in a focused" 725 + " state"); 726 return HANDLED; 727 case START_CALL_STREAMING: 728 transitionTo(mStreamingFocusState); 729 return HANDLED; 730 default: 731 // The forced focus switch commands are handled by BaseState. 732 return NOT_HANDLED; 733 } 734 } 735 } 736 737 private class StreamingFocusState extends BaseState { 738 @Override enter()739 public void enter() { 740 Log.i(LOG_TAG, "Audio focus entering streaming state"); 741 mLocalLog.log("Enter Streaming"); 742 mLocalLog.log("Mode MODE_COMMUNICATION_REDIRECT"); 743 mAudioManager.setMode(AudioManager.MODE_COMMUNICATION_REDIRECT); 744 mMostRecentMode = AudioManager.MODE_NORMAL; 745 mCallAudioManager.setCallAudioRouteFocusState(CallAudioRouteStateMachine.ACTIVE_FOCUS); 746 mCallAudioManager.getCallAudioRouteAdapter().sendMessageWithSessionInfo( 747 CallAudioRouteStateMachine.STREAMING_FORCE_ENABLED); 748 } 749 preExit()750 private void preExit() { 751 mCallAudioManager.getCallAudioRouteAdapter().sendMessageWithSessionInfo( 752 CallAudioRouteStateMachine.STREAMING_FORCE_DISABLED); 753 } 754 755 @Override processMessage(Message msg)756 public boolean processMessage(Message msg) { 757 if (super.processMessage(msg) == HANDLED) { 758 return HANDLED; 759 } 760 MessageArgs args = (MessageArgs) msg.obj; 761 switch (msg.what) { 762 case NO_MORE_ACTIVE_OR_DIALING_CALLS: 763 // Switch to either ringing, holding, or inactive 764 transitionTo(calculateProperStateFromArgs(args)); 765 return HANDLED; 766 case NO_MORE_RINGING_CALLS: 767 // Do nothing. 768 return HANDLED; 769 case NO_MORE_HOLDING_CALLS: 770 // Do nothing. 771 return HANDLED; 772 case NO_MORE_AUDIO_PROCESSING_CALLS: 773 // Do nothing. 774 return HANDLED; 775 case NEW_ACTIVE_OR_DIALING_CALL: 776 // Only possible for emergency call 777 BaseState destState = calculateProperStateFromArgs(args); 778 if (destState != this) { 779 preExit(); 780 transitionTo(destState); 781 } 782 return HANDLED; 783 case NEW_RINGING_CALL: 784 // Only possible for emergency call 785 preExit(); 786 transitionTo(mRingingFocusState); 787 return HANDLED; 788 case NEW_HOLDING_CALL: 789 // Do nothing. 790 return HANDLED; 791 case NEW_AUDIO_PROCESSING_CALL: 792 // Do nothing. 793 return HANDLED; 794 case START_CALL_STREAMING: 795 // Can happen as a duplicate message 796 return HANDLED; 797 case TONE_STARTED_PLAYING: 798 // Do nothing. 799 return HANDLED; 800 case STOP_CALL_STREAMING: 801 transitionTo(calculateProperStateFromArgs(args)); 802 return HANDLED; 803 default: 804 // The forced focus switch commands are handled by BaseState. 805 return NOT_HANDLED; 806 } 807 } 808 } 809 810 /** 811 * This class is used for calls on hold and end-of-call tones. 812 */ 813 private class OtherFocusState extends BaseState { 814 @Override enter()815 public void enter() { 816 Log.i(LOG_TAG, "Audio focus entering TONE/HOLDING state"); 817 mLocalLog.log("Enter TONE/HOLDING"); 818 if (mFeatureFlags.telecomResolveHiddenDependencies()) { 819 mCurrentAudioFocusRequest = CALL_AUDIO_FOCUS_REQUEST; 820 mAudioManager.requestAudioFocus(CALL_AUDIO_FOCUS_REQUEST); 821 } else { 822 mAudioManager.requestAudioFocusForCall(AudioManager.STREAM_VOICE_CALL, 823 AudioManager.AUDIOFOCUS_GAIN_TRANSIENT); 824 } 825 mAudioManager.setMode(mMostRecentMode); 826 mLocalLog.log("Mode " + mMostRecentMode); 827 mCallAudioManager.setCallAudioRouteFocusState(CallAudioRouteStateMachine.ACTIVE_FOCUS); 828 } 829 830 @Override processMessage(Message msg)831 public boolean processMessage(Message msg) { 832 if (super.processMessage(msg) == HANDLED) { 833 return HANDLED; 834 } 835 MessageArgs args = (MessageArgs) msg.obj; 836 switch (msg.what) { 837 case NO_MORE_HOLDING_CALLS: 838 if (args.hasActiveOrDialingCalls) { 839 transitionTo(args.foregroundCallIsVoip 840 ? mVoipCallFocusState : mSimCallFocusState); 841 } else if (args.hasRingingCalls) { 842 transitionTo(mRingingFocusState); 843 } else if (!args.isTonePlaying) { 844 transitionTo(mUnfocusedState); 845 } 846 // Do nothing if a tone is playing. 847 return HANDLED; 848 case NEW_ACTIVE_OR_DIALING_CALL: 849 transitionTo(args.foregroundCallIsVoip 850 ? mVoipCallFocusState : mSimCallFocusState); 851 return HANDLED; 852 case NEW_RINGING_CALL: 853 // TODO: consider whether to move this into MessageArgs if more things start 854 // to use it. 855 if (args.hasHoldingCalls && mSystemStateHelper.isDeviceAtEar()) { 856 mCallAudioManager.startCallWaiting( 857 "Device is at ear with held call"); 858 } else { 859 transitionTo(mRingingFocusState); 860 } 861 return HANDLED; 862 case NEW_HOLDING_CALL: 863 // Do nothing. 864 return HANDLED; 865 case NO_MORE_RINGING_CALLS: 866 // If there are no more ringing calls in this state, then stop any call-waiting 867 // tones that may be playing. 868 mCallAudioManager.stopCallWaiting(); 869 return HANDLED; 870 case TONE_STOPPED_PLAYING: 871 transitionTo(calculateProperStateFromArgs(args)); 872 return HANDLED; 873 case AUDIO_OPERATIONS_COMPLETE: 874 Log.w(LOG_TAG, "Should not be seeing AUDIO_OPERATIONS_COMPLETE in a focused" 875 + " state"); 876 return HANDLED; 877 default: 878 return NOT_HANDLED; 879 } 880 } 881 } 882 883 private static final String LOG_TAG = CallAudioModeStateMachine.class.getSimpleName(); 884 885 private final BaseState mUnfocusedState = new UnfocusedState(); 886 private final BaseState mRingingFocusState = new RingingFocusState(); 887 private final BaseState mSimCallFocusState = new SimCallFocusState(); 888 private final BaseState mVoipCallFocusState = new VoipCallFocusState(); 889 private final BaseState mAudioProcessingFocusState = new AudioProcessingFocusState(); 890 private final BaseState mStreamingFocusState = new StreamingFocusState(); 891 private final BaseState mOtherFocusState = new OtherFocusState(); 892 893 private final AudioManager mAudioManager; 894 private final SystemStateHelper mSystemStateHelper; 895 private CallAudioManager mCallAudioManager; 896 private FeatureFlags mFeatureFlags; 897 private CallAudioCommunicationDeviceTracker mCommunicationDeviceTracker; 898 899 private int mMostRecentMode; 900 private boolean mIsInitialized = false; 901 CallAudioModeStateMachine(SystemStateHelper systemStateHelper, AudioManager audioManager, FeatureFlags featureFlags, CallAudioCommunicationDeviceTracker callAudioCommunicationDeviceTracker)902 public CallAudioModeStateMachine(SystemStateHelper systemStateHelper, 903 AudioManager audioManager, FeatureFlags featureFlags, 904 CallAudioCommunicationDeviceTracker callAudioCommunicationDeviceTracker) { 905 super(CallAudioModeStateMachine.class.getSimpleName()); 906 mAudioManager = audioManager; 907 mSystemStateHelper = systemStateHelper; 908 mMostRecentMode = AudioManager.MODE_NORMAL; 909 mFeatureFlags = featureFlags; 910 mCommunicationDeviceTracker = callAudioCommunicationDeviceTracker; 911 912 createStates(); 913 } 914 915 /** 916 * Used for testing 917 */ CallAudioModeStateMachine(SystemStateHelper systemStateHelper, AudioManager audioManager, Looper looper, FeatureFlags featureFlags, CallAudioCommunicationDeviceTracker communicationDeviceTracker)918 public CallAudioModeStateMachine(SystemStateHelper systemStateHelper, 919 AudioManager audioManager, Looper looper, FeatureFlags featureFlags, 920 CallAudioCommunicationDeviceTracker communicationDeviceTracker) { 921 super(CallAudioModeStateMachine.class.getSimpleName(), looper); 922 mAudioManager = audioManager; 923 mSystemStateHelper = systemStateHelper; 924 mMostRecentMode = AudioManager.MODE_NORMAL; 925 mFeatureFlags = featureFlags; 926 mCommunicationDeviceTracker = communicationDeviceTracker; 927 928 createStates(); 929 } 930 createStates()931 private void createStates() { 932 addState(mUnfocusedState); 933 addState(mRingingFocusState); 934 addState(mSimCallFocusState); 935 addState(mVoipCallFocusState); 936 addState(mAudioProcessingFocusState); 937 addState(mStreamingFocusState); 938 addState(mOtherFocusState); 939 setInitialState(mUnfocusedState); 940 start(); 941 sendMessage(INITIALIZE, new MessageArgs.Builder() 942 .setHasActiveOrDialingCalls(false) 943 .setHasRingingCalls(false) 944 .setHasHoldingCalls(false) 945 .setIsTonePlaying(false) 946 .setForegroundCallIsVoip(false) 947 .setIsStreaming(false) 948 .setSession(Log.createSubsession()) 949 .build()); 950 } 951 setCallAudioManager(CallAudioManager callAudioManager)952 public void setCallAudioManager(CallAudioManager callAudioManager) { 953 mCallAudioManager = callAudioManager; 954 } 955 getCurrentStateName()956 public String getCurrentStateName() { 957 IState currentState = getCurrentState(); 958 return currentState == null ? "no state" : currentState.getName(); 959 } 960 sendMessageWithArgs(int messageCode, MessageArgs args)961 public void sendMessageWithArgs(int messageCode, MessageArgs args) { 962 sendMessage(messageCode, args); 963 } 964 965 @Override onPreHandleMessage(Message msg)966 protected void onPreHandleMessage(Message msg) { 967 if (msg.obj != null && msg.obj instanceof MessageArgs) { 968 Log.continueSession(((MessageArgs) msg.obj).session, "CAMSM.pM_" + msg.what); 969 Log.i(LOG_TAG, "Message received: %s.", MESSAGE_CODE_TO_NAME.get(msg.what)); 970 } else if (msg.what == RUN_RUNNABLE && msg.obj instanceof Runnable) { 971 Log.i(LOG_TAG, "Running runnable for testing"); 972 } else { 973 Log.w(LOG_TAG, "Message sent must be of type nonnull MessageArgs, but got " + 974 (msg.obj == null ? "null" : msg.obj.getClass().getSimpleName())); 975 Log.w(LOG_TAG, "The message was of code %d = %s", 976 msg.what, MESSAGE_CODE_TO_NAME.get(msg.what)); 977 } 978 } 979 dumpPendingMessages(IndentingPrintWriter pw)980 public void dumpPendingMessages(IndentingPrintWriter pw) { 981 getHandler().getLooper().dump(pw::println, ""); 982 } 983 dump(IndentingPrintWriter pw)984 public void dump(IndentingPrintWriter pw) { 985 pw.println("History:"); 986 mLocalLog.dump(pw); 987 pw.println("Pending Msg:"); 988 dumpPendingMessages(pw); 989 } 990 991 @Override onPostHandleMessage(Message msg)992 protected void onPostHandleMessage(Message msg) { 993 Log.endSession(); 994 } 995 calculateProperStateFromArgs(MessageArgs args)996 private BaseState calculateProperStateFromArgs(MessageArgs args) { 997 // If there are active, audio-processing, holding, or ringing calls, 998 // switch to the appropriate focus. 999 // Otherwise abandon focus. 1000 1001 // The order matters here. If there is streaming call, holding streaming route for them 1002 // takes priority. After that, holding focus for active calls takes priority. After that, we 1003 // want to prioritize holding calls over ringing calls so that when a call-waiting call gets 1004 // answered, there's no transition in and out of the ringing focus state. After that, we 1005 // want tones since we actually hold focus during them, then the audio processing state 1006 // because that will release focus. 1007 if (args.isStreaming) { 1008 return mSimCallFocusState; 1009 } else if (args.hasActiveOrDialingCalls) { 1010 if (args.foregroundCallIsVoip) { 1011 return mVoipCallFocusState; 1012 } else { 1013 return mSimCallFocusState; 1014 } 1015 } else if (args.hasHoldingCalls) { 1016 return mOtherFocusState; 1017 } else if (args.hasRingingCalls) { 1018 return mRingingFocusState; 1019 } else if (args.isTonePlaying) { 1020 return mOtherFocusState; 1021 } else if (args.hasAudioProcessingCalls) { 1022 return mAudioProcessingFocusState; 1023 } 1024 return mUnfocusedState; 1025 } 1026 1027 } 1028