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