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