Home | History | Annotate | Download | only in telecom
      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.AudioManager;
     20 import android.os.Message;
     21 import android.util.SparseArray;
     22 
     23 import com.android.internal.util.IState;
     24 import com.android.internal.util.State;
     25 import com.android.internal.util.StateMachine;
     26 
     27 public class CallAudioModeStateMachine extends StateMachine {
     28     public static class MessageArgs {
     29         public boolean hasActiveOrDialingCalls;
     30         public boolean hasRingingCalls;
     31         public boolean hasHoldingCalls;
     32         public boolean isTonePlaying;
     33         public boolean foregroundCallIsVoip;
     34         public Session session;
     35 
     36         public MessageArgs(boolean hasActiveOrDialingCalls, boolean hasRingingCalls,
     37                 boolean hasHoldingCalls, boolean isTonePlaying, boolean foregroundCallIsVoip,
     38                 Session session) {
     39             this.hasActiveOrDialingCalls = hasActiveOrDialingCalls;
     40             this.hasRingingCalls = hasRingingCalls;
     41             this.hasHoldingCalls = hasHoldingCalls;
     42             this.isTonePlaying = isTonePlaying;
     43             this.foregroundCallIsVoip = foregroundCallIsVoip;
     44             this.session = session;
     45         }
     46 
     47         public MessageArgs() {
     48             this.session = Log.createSubsession();
     49         }
     50 
     51         @Override
     52         public String toString() {
     53             return "MessageArgs{" +
     54                     "hasActiveCalls=" + hasActiveOrDialingCalls +
     55                     ", hasRingingCalls=" + hasRingingCalls +
     56                     ", hasHoldingCalls=" + hasHoldingCalls +
     57                     ", isTonePlaying=" + isTonePlaying +
     58                     ", foregroundCallIsVoip=" + foregroundCallIsVoip +
     59                     ", session=" + session +
     60                     '}';
     61         }
     62     }
     63 
     64     public static final int INITIALIZE = 1;
     65     // These ENTER_*_FOCUS commands are for testing.
     66     public static final int ENTER_CALL_FOCUS_FOR_TESTING = 2;
     67     public static final int ENTER_COMMS_FOCUS_FOR_TESTING = 3;
     68     public static final int ENTER_RING_FOCUS_FOR_TESTING = 4;
     69     public static final int ENTER_TONE_OR_HOLD_FOCUS_FOR_TESTING = 5;
     70     public static final int ABANDON_FOCUS_FOR_TESTING = 6;
     71 
     72     public static final int NO_MORE_ACTIVE_OR_DIALING_CALLS = 1001;
     73     public static final int NO_MORE_RINGING_CALLS = 1002;
     74     public static final int NO_MORE_HOLDING_CALLS = 1003;
     75 
     76     public static final int NEW_ACTIVE_OR_DIALING_CALL = 2001;
     77     public static final int NEW_RINGING_CALL = 2002;
     78     public static final int NEW_HOLDING_CALL = 2003;
     79     public static final int MT_AUDIO_SPEEDUP_FOR_RINGING_CALL = 2004;
     80 
     81     public static final int TONE_STARTED_PLAYING = 3001;
     82     public static final int TONE_STOPPED_PLAYING = 3002;
     83 
     84     public static final int FOREGROUND_VOIP_MODE_CHANGE = 4001;
     85 
     86     public static final int RUN_RUNNABLE = 9001;
     87 
     88     private static final SparseArray<String> MESSAGE_CODE_TO_NAME = new SparseArray<String>() {{
     89         put(ENTER_CALL_FOCUS_FOR_TESTING, "ENTER_CALL_FOCUS_FOR_TESTING");
     90         put(ENTER_COMMS_FOCUS_FOR_TESTING, "ENTER_COMMS_FOCUS_FOR_TESTING");
     91         put(ENTER_RING_FOCUS_FOR_TESTING, "ENTER_RING_FOCUS_FOR_TESTING");
     92         put(ENTER_TONE_OR_HOLD_FOCUS_FOR_TESTING, "ENTER_TONE_OR_HOLD_FOCUS_FOR_TESTING");
     93         put(ABANDON_FOCUS_FOR_TESTING, "ABANDON_FOCUS_FOR_TESTING");
     94         put(NO_MORE_ACTIVE_OR_DIALING_CALLS, "NO_MORE_ACTIVE_OR_DIALING_CALLS");
     95         put(NO_MORE_RINGING_CALLS, "NO_MORE_RINGING_CALLS");
     96         put(NO_MORE_HOLDING_CALLS, "NO_MORE_HOLDING_CALLS");
     97         put(NEW_ACTIVE_OR_DIALING_CALL, "NEW_ACTIVE_OR_DIALING_CALL");
     98         put(NEW_RINGING_CALL, "NEW_RINGING_CALL");
     99         put(NEW_HOLDING_CALL, "NEW_HOLDING_CALL");
    100         put(MT_AUDIO_SPEEDUP_FOR_RINGING_CALL, "MT_AUDIO_SPEEDUP_FOR_RINGING_CALL");
    101         put(TONE_STARTED_PLAYING, "TONE_STARTED_PLAYING");
    102         put(TONE_STOPPED_PLAYING, "TONE_STOPPED_PLAYING");
    103         put(FOREGROUND_VOIP_MODE_CHANGE, "FOREGROUND_VOIP_MODE_CHANGE");
    104 
    105         put(RUN_RUNNABLE, "RUN_RUNNABLE");
    106     }};
    107 
    108     public static final String TONE_HOLD_STATE_NAME = OtherFocusState.class.getSimpleName();
    109     public static final String UNFOCUSED_STATE_NAME = UnfocusedState.class.getSimpleName();
    110     public static final String CALL_STATE_NAME = SimCallFocusState.class.getSimpleName();
    111     public static final String RING_STATE_NAME = RingingFocusState.class.getSimpleName();
    112     public static final String COMMS_STATE_NAME = VoipCallFocusState.class.getSimpleName();
    113 
    114     private class BaseState extends State {
    115         @Override
    116         public boolean processMessage(Message msg) {
    117             switch (msg.what) {
    118                 case ENTER_CALL_FOCUS_FOR_TESTING:
    119                     transitionTo(mSimCallFocusState);
    120                     return HANDLED;
    121                 case ENTER_COMMS_FOCUS_FOR_TESTING:
    122                     transitionTo(mVoipCallFocusState);
    123                     return HANDLED;
    124                 case ENTER_RING_FOCUS_FOR_TESTING:
    125                     transitionTo(mRingingFocusState);
    126                     return HANDLED;
    127                 case ENTER_TONE_OR_HOLD_FOCUS_FOR_TESTING:
    128                     transitionTo(mOtherFocusState);
    129                     return HANDLED;
    130                 case ABANDON_FOCUS_FOR_TESTING:
    131                     transitionTo(mUnfocusedState);
    132                     return HANDLED;
    133                 case INITIALIZE:
    134                     mIsInitialized = true;
    135                     return HANDLED;
    136                 case RUN_RUNNABLE:
    137                     java.lang.Runnable r = (java.lang.Runnable) msg.obj;
    138                     r.run();
    139                     return HANDLED;
    140                 default:
    141                     return NOT_HANDLED;
    142             }
    143         }
    144     }
    145 
    146     private class UnfocusedState extends BaseState {
    147         @Override
    148         public void enter() {
    149             if (mIsInitialized) {
    150                 Log.i(LOG_TAG, "Abandoning audio focus: now UNFOCUSED");
    151                 mAudioManager.abandonAudioFocusForCall();
    152                 mAudioManager.setMode(AudioManager.MODE_NORMAL);
    153 
    154                 mMostRecentMode = AudioManager.MODE_NORMAL;
    155                 mCallAudioManager.setCallAudioRouteFocusState(CallAudioRouteStateMachine.NO_FOCUS);
    156             }
    157         }
    158 
    159         @Override
    160         public boolean processMessage(Message msg) {
    161             if (super.processMessage(msg) == HANDLED) {
    162                 return HANDLED;
    163             }
    164             MessageArgs args = (MessageArgs) msg.obj;
    165             switch (msg.what) {
    166                 case NO_MORE_ACTIVE_OR_DIALING_CALLS:
    167                     // Do nothing.
    168                     return HANDLED;
    169                 case NO_MORE_RINGING_CALLS:
    170                     // Do nothing.
    171                     return HANDLED;
    172                 case NO_MORE_HOLDING_CALLS:
    173                     // Do nothing.
    174                     return HANDLED;
    175                 case NEW_ACTIVE_OR_DIALING_CALL:
    176                     transitionTo(args.foregroundCallIsVoip
    177                             ? mVoipCallFocusState : mSimCallFocusState);
    178                     return HANDLED;
    179                 case NEW_RINGING_CALL:
    180                     transitionTo(mRingingFocusState);
    181                     return HANDLED;
    182                 case NEW_HOLDING_CALL:
    183                     // This really shouldn't happen, but transition to the focused state anyway.
    184                     Log.w(LOG_TAG, "Call was surprisingly put into hold from an unknown state." +
    185                             " Args are: \n" + args.toString());
    186                     transitionTo(mOtherFocusState);
    187                     return HANDLED;
    188                 case TONE_STARTED_PLAYING:
    189                     // This shouldn't happen either, but perform the action anyway.
    190                     Log.w(LOG_TAG, "Tone started playing unexpectedly. Args are: \n"
    191                             + args.toString());
    192                     return HANDLED;
    193                 default:
    194                     // The forced focus switch commands are handled by BaseState.
    195                     return NOT_HANDLED;
    196             }
    197         }
    198     }
    199 
    200     private class RingingFocusState extends BaseState {
    201         @Override
    202         public void enter() {
    203             Log.i(LOG_TAG, "Audio focus entering RINGING state");
    204             if (mCallAudioManager.startRinging()) {
    205                 mAudioManager.requestAudioFocusForCall(AudioManager.STREAM_RING,
    206                         AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
    207                 if (mMostRecentMode == AudioManager.MODE_IN_CALL) {
    208                     // Preserving behavior from the old CallAudioManager.
    209                     Log.i(LOG_TAG, "Transition from IN_CALL -> RINGTONE."
    210                             + "  Resetting to NORMAL first.");
    211                     mAudioManager.setMode(AudioManager.MODE_NORMAL);
    212                 }
    213                 mAudioManager.setMode(AudioManager.MODE_RINGTONE);
    214                 mCallAudioManager.setCallAudioRouteFocusState(CallAudioRouteStateMachine.RINGING_FOCUS);
    215             } else {
    216                 Log.i(LOG_TAG, "Entering RINGING but not acquiring focus -- silent ringtone");
    217             }
    218 
    219             mCallAudioManager.stopCallWaiting();
    220         }
    221 
    222         @Override
    223         public void exit() {
    224             // Audio mode and audio stream will be set by the next state.
    225             mCallAudioManager.stopRinging();
    226         }
    227 
    228         @Override
    229         public boolean processMessage(Message msg) {
    230             if (super.processMessage(msg) == HANDLED) {
    231                 return HANDLED;
    232             }
    233             MessageArgs args = (MessageArgs) msg.obj;
    234             switch (msg.what) {
    235                 case NO_MORE_ACTIVE_OR_DIALING_CALLS:
    236                     // Do nothing. Loss of an active call should not impact ringer.
    237                     return HANDLED;
    238                 case NO_MORE_HOLDING_CALLS:
    239                     // Do nothing and keep ringing.
    240                     return HANDLED;
    241                 case NO_MORE_RINGING_CALLS:
    242                     // If there are active or holding calls, switch to the appropriate focus.
    243                     // Otherwise abandon focus.
    244                     if (args.hasActiveOrDialingCalls) {
    245                         if (args.foregroundCallIsVoip) {
    246                             transitionTo(mVoipCallFocusState);
    247                         } else {
    248                             transitionTo(mSimCallFocusState);
    249                         }
    250                     } else if (args.hasHoldingCalls || args.isTonePlaying) {
    251                         transitionTo(mOtherFocusState);
    252                     } else {
    253                         transitionTo(mUnfocusedState);
    254                     }
    255                     return HANDLED;
    256                 case NEW_ACTIVE_OR_DIALING_CALL:
    257                     // If a call becomes active suddenly, give it priority over ringing.
    258                     transitionTo(args.foregroundCallIsVoip
    259                             ? mVoipCallFocusState : mSimCallFocusState);
    260                     return HANDLED;
    261                 case NEW_RINGING_CALL:
    262                     Log.w(LOG_TAG, "Unexpected behavior! New ringing call appeared while in " +
    263                             "ringing state.");
    264                     return HANDLED;
    265                 case NEW_HOLDING_CALL:
    266                     // This really shouldn't happen, but transition to the focused state anyway.
    267                     Log.w(LOG_TAG, "Call was surprisingly put into hold while ringing." +
    268                             " Args are: " + args.toString());
    269                     transitionTo(mOtherFocusState);
    270                     return HANDLED;
    271                 case MT_AUDIO_SPEEDUP_FOR_RINGING_CALL:
    272                     // This happens when an IMS call is answered by the in-call UI. Special case
    273                     // that we have to deal with for some reason.
    274 
    275                     // VOIP calls should never invoke this mechanism, so transition directly to
    276                     // the sim call focus state.
    277                     transitionTo(mSimCallFocusState);
    278                     return HANDLED;
    279                 default:
    280                     // The forced focus switch commands are handled by BaseState.
    281                     return NOT_HANDLED;
    282             }
    283         }
    284     }
    285 
    286     private class SimCallFocusState extends BaseState {
    287         @Override
    288         public void enter() {
    289             Log.i(LOG_TAG, "Audio focus entering SIM CALL state");
    290             mAudioManager.requestAudioFocusForCall(AudioManager.STREAM_VOICE_CALL,
    291                     AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
    292             mAudioManager.setMode(AudioManager.MODE_IN_CALL);
    293             mMostRecentMode = AudioManager.MODE_IN_CALL;
    294             mCallAudioManager.setCallAudioRouteFocusState(CallAudioRouteStateMachine.ACTIVE_FOCUS);
    295         }
    296 
    297         @Override
    298         public boolean processMessage(Message msg) {
    299             if (super.processMessage(msg) == HANDLED) {
    300                 return HANDLED;
    301             }
    302             MessageArgs args = (MessageArgs) msg.obj;
    303             switch (msg.what) {
    304                 case NO_MORE_ACTIVE_OR_DIALING_CALLS:
    305                     // Switch to either ringing, holding, or inactive
    306                     transitionTo(destinationStateAfterNoMoreActiveCalls(args));
    307                     return HANDLED;
    308                 case NO_MORE_RINGING_CALLS:
    309                     // Don't transition state, but stop any call-waiting tones that may have been
    310                     // playing.
    311                     if (args.isTonePlaying) {
    312                         mCallAudioManager.stopCallWaiting();
    313                     }
    314                     // If a MT-audio-speedup call gets disconnected by the connection service
    315                     // concurrently with the user answering it, we may get this message
    316                     // indicating that a ringing call has disconnected while this state machine
    317                     // is in the SimCallFocusState.
    318                     if (!args.hasActiveOrDialingCalls) {
    319                         transitionTo(destinationStateAfterNoMoreActiveCalls(args));
    320                     }
    321                     return HANDLED;
    322                 case NO_MORE_HOLDING_CALLS:
    323                     // Do nothing.
    324                     return HANDLED;
    325                 case NEW_ACTIVE_OR_DIALING_CALL:
    326                     // Do nothing. Already active.
    327                     return HANDLED;
    328                 case NEW_RINGING_CALL:
    329                     // Don't make a call ring over an active call, but do play a call waiting tone.
    330                     mCallAudioManager.startCallWaiting();
    331                     return HANDLED;
    332                 case NEW_HOLDING_CALL:
    333                     // Don't do anything now. Putting an active call on hold will be handled when
    334                     // NO_MORE_ACTIVE_CALLS is processed.
    335                     return HANDLED;
    336                 case FOREGROUND_VOIP_MODE_CHANGE:
    337                     if (args.foregroundCallIsVoip) {
    338                         transitionTo(mVoipCallFocusState);
    339                     }
    340                     return HANDLED;
    341                 default:
    342                     // The forced focus switch commands are handled by BaseState.
    343                     return NOT_HANDLED;
    344             }
    345         }
    346     }
    347 
    348     private class VoipCallFocusState extends BaseState {
    349         @Override
    350         public void enter() {
    351             Log.i(LOG_TAG, "Audio focus entering VOIP CALL state");
    352             mAudioManager.requestAudioFocusForCall(AudioManager.STREAM_VOICE_CALL,
    353                     AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
    354             mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
    355             mMostRecentMode = AudioManager.MODE_IN_COMMUNICATION;
    356             mCallAudioManager.setCallAudioRouteFocusState(CallAudioRouteStateMachine.ACTIVE_FOCUS);
    357         }
    358 
    359         @Override
    360         public boolean processMessage(Message msg) {
    361             if (super.processMessage(msg) == HANDLED) {
    362                 return HANDLED;
    363             }
    364             MessageArgs args = (MessageArgs) msg.obj;
    365             switch (msg.what) {
    366                 case NO_MORE_ACTIVE_OR_DIALING_CALLS:
    367                     // Switch to either ringing, holding, or inactive
    368                     transitionTo(destinationStateAfterNoMoreActiveCalls(args));
    369                     return HANDLED;
    370                 case NO_MORE_RINGING_CALLS:
    371                     // Don't transition state, but stop any call-waiting tones that may have been
    372                     // playing.
    373                     if (args.isTonePlaying) {
    374                         mCallAudioManager.stopCallWaiting();
    375                     }
    376                     return HANDLED;
    377                 case NO_MORE_HOLDING_CALLS:
    378                     // Do nothing.
    379                     return HANDLED;
    380                 case NEW_ACTIVE_OR_DIALING_CALL:
    381                     // Do nothing. Already active.
    382                     return HANDLED;
    383                 case NEW_RINGING_CALL:
    384                     // Don't make a call ring over an active call, but do play a call waiting tone.
    385                     mCallAudioManager.startCallWaiting();
    386                     return HANDLED;
    387                 case NEW_HOLDING_CALL:
    388                     // Don't do anything now. Putting an active call on hold will be handled when
    389                     // NO_MORE_ACTIVE_CALLS is processed.
    390                     return HANDLED;
    391                 case FOREGROUND_VOIP_MODE_CHANGE:
    392                     if (!args.foregroundCallIsVoip) {
    393                         transitionTo(mSimCallFocusState);
    394                     }
    395                     return HANDLED;
    396                 default:
    397                     // The forced focus switch commands are handled by BaseState.
    398                     return NOT_HANDLED;
    399             }
    400         }
    401     }
    402 
    403     /**
    404      * This class is used for calls on hold and end-of-call tones.
    405      */
    406     private class OtherFocusState extends BaseState {
    407         @Override
    408         public void enter() {
    409             Log.i(LOG_TAG, "Audio focus entering TONE/HOLDING state");
    410             mAudioManager.requestAudioFocusForCall(AudioManager.STREAM_VOICE_CALL,
    411                     AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
    412             mAudioManager.setMode(mMostRecentMode);
    413             mCallAudioManager.setCallAudioRouteFocusState(CallAudioRouteStateMachine.ACTIVE_FOCUS);
    414         }
    415 
    416         @Override
    417         public boolean processMessage(Message msg) {
    418             if (super.processMessage(msg) == HANDLED) {
    419                 return HANDLED;
    420             }
    421             MessageArgs args = (MessageArgs) msg.obj;
    422             switch (msg.what) {
    423                 case NO_MORE_HOLDING_CALLS:
    424                     if (args.hasActiveOrDialingCalls) {
    425                         transitionTo(args.foregroundCallIsVoip
    426                                 ? mVoipCallFocusState : mSimCallFocusState);
    427                     } else if (args.hasRingingCalls) {
    428                         transitionTo(mRingingFocusState);
    429                     } else if (!args.isTonePlaying) {
    430                         transitionTo(mUnfocusedState);
    431                     }
    432                     // Do nothing if a tone is playing.
    433                     return HANDLED;
    434                 case NEW_ACTIVE_OR_DIALING_CALL:
    435                     transitionTo(args.foregroundCallIsVoip
    436                             ? mVoipCallFocusState : mSimCallFocusState);
    437                     return HANDLED;
    438                 case NEW_RINGING_CALL:
    439                     // Apparently this is current behavior. Should this be the case?
    440                     transitionTo(mRingingFocusState);
    441                     return HANDLED;
    442                 case NEW_HOLDING_CALL:
    443                     // Do nothing.
    444                     return HANDLED;
    445                 case NO_MORE_RINGING_CALLS:
    446                     // If there are no more ringing calls in this state, then stop any call-waiting
    447                     // tones that may be playing.
    448                     mCallAudioManager.stopCallWaiting();
    449                     return HANDLED;
    450                 case TONE_STOPPED_PLAYING:
    451                     transitionTo(destinationStateAfterNoMoreActiveCalls(args));
    452                 default:
    453                     return NOT_HANDLED;
    454             }
    455         }
    456     }
    457 
    458     private static final String LOG_TAG = CallAudioModeStateMachine.class.getSimpleName();
    459 
    460     private final BaseState mUnfocusedState = new UnfocusedState();
    461     private final BaseState mRingingFocusState = new RingingFocusState();
    462     private final BaseState mSimCallFocusState = new SimCallFocusState();
    463     private final BaseState mVoipCallFocusState = new VoipCallFocusState();
    464     private final BaseState mOtherFocusState = new OtherFocusState();
    465 
    466     private final AudioManager mAudioManager;
    467     private CallAudioManager mCallAudioManager;
    468 
    469     private int mMostRecentMode;
    470     private boolean mIsInitialized = false;
    471 
    472     public CallAudioModeStateMachine(AudioManager audioManager) {
    473         super(CallAudioModeStateMachine.class.getSimpleName());
    474         mAudioManager = audioManager;
    475         mMostRecentMode = AudioManager.MODE_NORMAL;
    476 
    477         addState(mUnfocusedState);
    478         addState(mRingingFocusState);
    479         addState(mSimCallFocusState);
    480         addState(mVoipCallFocusState);
    481         addState(mOtherFocusState);
    482         setInitialState(mUnfocusedState);
    483         start();
    484         sendMessage(INITIALIZE, new MessageArgs());
    485     }
    486 
    487     public void setCallAudioManager(CallAudioManager callAudioManager) {
    488         mCallAudioManager = callAudioManager;
    489     }
    490 
    491     public String getCurrentStateName() {
    492         IState currentState = getCurrentState();
    493         return currentState == null ? "no state" : currentState.getName();
    494     }
    495 
    496     public void sendMessageWithArgs(int messageCode, MessageArgs args) {
    497         sendMessage(messageCode, args);
    498     }
    499 
    500     @Override
    501     protected void onPreHandleMessage(Message msg) {
    502         if (msg.obj != null && msg.obj instanceof MessageArgs) {
    503             Log.continueSession(((MessageArgs) msg.obj).session, "CAMSM.pM_" + msg.what);
    504             Log.i(LOG_TAG, "Message received: %s.", MESSAGE_CODE_TO_NAME.get(msg.what));
    505         } else if (msg.what == RUN_RUNNABLE && msg.obj instanceof Runnable) {
    506             Log.i(LOG_TAG, "Running runnable for testing");
    507         } else {
    508                 Log.w(LOG_TAG, "Message sent must be of type nonnull MessageArgs, but got " +
    509                         (msg.obj == null ? "null" : msg.obj.getClass().getSimpleName()));
    510                 Log.w(LOG_TAG, "The message was of code %d = %s",
    511                         msg.what, MESSAGE_CODE_TO_NAME.get(msg.what));
    512         }
    513     }
    514 
    515     @Override
    516     protected void onPostHandleMessage(Message msg) {
    517         Log.endSession();
    518     }
    519 
    520     private BaseState destinationStateAfterNoMoreActiveCalls(MessageArgs args) {
    521         if (args.hasHoldingCalls) {
    522             return mOtherFocusState;
    523         } else if (args.hasRingingCalls) {
    524             return mRingingFocusState;
    525         } else if (args.isTonePlaying) {
    526             return mOtherFocusState;
    527         } else {
    528             return mUnfocusedState;
    529         }
    530     }
    531 }