PhoneUtils.java revision bfb6832c4bcc535aef12b07ac5bcf4a973c65d00
17d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon/*
27d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon * Copyright (C) 2006 The Android Open Source Project
37d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon *
47d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon * Licensed under the Apache License, Version 2.0 (the "License");
57d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon * you may not use this file except in compliance with the License.
67d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon * You may obtain a copy of the License at
77d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon *
87d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon *      http://www.apache.org/licenses/LICENSE-2.0
97d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon *
107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon * Unless required by applicable law or agreed to in writing, software
117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon * distributed under the License is distributed on an "AS IS" BASIS,
127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon * See the License for the specific language governing permissions and
147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon * limitations under the License.
157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon */
167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonpackage com.android.phone;
187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.app.AlertDialog;
207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.app.Dialog;
217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.app.ProgressDialog;
227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.bluetooth.IBluetoothHeadsetPhone;
237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.content.ActivityNotFoundException;
24bfb6832c4bcc535aef12b07ac5bcf4a973c65d00Sailesh Nepalimport android.content.ComponentName;
257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.content.Context;
267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.content.DialogInterface;
277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.content.Intent;
287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.content.pm.ApplicationInfo;
297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.content.pm.PackageManager;
307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.content.res.Configuration;
317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.graphics.drawable.Drawable;
327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.media.AudioManager;
337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.net.Uri;
347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.net.sip.SipManager;
357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.os.AsyncResult;
367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.os.Handler;
377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.os.Message;
387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.os.RemoteException;
397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.os.SystemProperties;
407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.telephony.PhoneNumberUtils;
417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.text.TextUtils;
427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.util.Log;
437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.view.KeyEvent;
447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.view.LayoutInflater;
457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.view.View;
467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.view.WindowManager;
477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.widget.EditText;
487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.widget.Toast;
497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport com.android.internal.telephony.Call;
517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport com.android.internal.telephony.CallManager;
527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport com.android.internal.telephony.CallStateException;
537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport com.android.internal.telephony.CallerInfo;
547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport com.android.internal.telephony.CallerInfoAsyncQuery;
557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport com.android.internal.telephony.Connection;
567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport com.android.internal.telephony.MmiCode;
577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport com.android.internal.telephony.Phone;
587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport com.android.internal.telephony.PhoneConstants;
59bfb6832c4bcc535aef12b07ac5bcf4a973c65d00Sailesh Nepalimport com.android.internal.telephony.PhoneFactory;
607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport com.android.internal.telephony.TelephonyCapabilities;
617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport com.android.internal.telephony.TelephonyProperties;
627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport com.android.internal.telephony.cdma.CdmaConnection;
637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport com.android.internal.telephony.sip.SipPhone;
64bfb6832c4bcc535aef12b07ac5bcf4a973c65d00Sailesh Nepalimport com.android.internal.telephony.thirdpartyphone.ThirdPartyPhone;
6569a691914e9b013a7ff52c129d8466c152ed7239Santos Cordonimport com.android.phone.CallGatewayManager.RawGatewayInfo;
667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport java.util.ArrayList;
687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport java.util.Arrays;
697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport java.util.Hashtable;
707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport java.util.Iterator;
717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport java.util.List;
727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon/**
747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon * Misc utilities for the Phone app.
757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon */
767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonpublic class PhoneUtils {
777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static final String LOG_TAG = "PhoneUtils";
787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2);
797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    // Do not check in with VDBG = true, since that may write PII to the system log.
817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static final boolean VDBG = false;
827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /** Control stack trace for Audio Mode settings */
847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static final boolean DBG_SETAUDIOMODE_STACK = false;
857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /** Identifier for the "Add Call" intent extra. */
877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static final String ADD_CALL_MODE_KEY = "add_call_mode";
887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    // Return codes from placeCall()
907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static final int CALL_STATUS_DIALED = 0;  // The number was successfully dialed
917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static final int CALL_STATUS_DIALED_MMI = 1;  // The specified number was an MMI code
927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static final int CALL_STATUS_FAILED = 2;  // The call failed
937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    // State of the Phone's audio modes
957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    // Each state can move to the other states, but within the state only certain
967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    //  transitions for AudioManager.setMode() are allowed.
977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static final int AUDIO_IDLE = 0;  /** audio behaviour at phone idle */
987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static final int AUDIO_RINGING = 1;  /** audio behaviour while ringing */
997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static final int AUDIO_OFFHOOK = 2;  /** audio behaviour while in call. */
1007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    // USSD string length for MMI operations
1027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static final int MIN_USSD_LEN = 1;
1037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static final int MAX_USSD_LEN = 160;
1047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /** Speaker state, persisting between wired headset connection events */
1067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static boolean sIsSpeakerEnabled = false;
1077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /** Hash table to store mute (Boolean) values based upon the connection.*/
1097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static Hashtable<Connection, Boolean> sConnectionMuteTable =
1107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        new Hashtable<Connection, Boolean>();
1117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /** Static handler for the connection/mute tracking */
1137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static ConnectionHandler mConnectionHandler;
1147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /** Phone state changed event*/
1167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static final int PHONE_STATE_CHANGED = -1;
1177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
118a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu    /** check status then decide whether answerCall */
119a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu    private static final int MSG_CHECK_STATUS_ANSWERCALL = 100;
120a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu
121a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu    /** poll phone DISCONNECTING status interval */
122a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu    private static final int DISCONNECTING_POLLING_INTERVAL_MS = 200;
123a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu
124a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu    /** poll phone DISCONNECTING status times limit */
125a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu    private static final int DISCONNECTING_POLLING_TIMES_LIMIT = 8;
126a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu
1277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /** Define for not a special CNAP string */
1287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static final int CNAP_SPECIAL_CASE_NO = -1;
1297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /** Noise suppression status as selected by user */
1317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static boolean sIsNoiseSuppressionEnabled = true;
1327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
133a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu    private static class FgRingCalls {
134a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu        private Call fgCall;
135a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu        private Call ringing;
136a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu        public FgRingCalls(Call fg, Call ring) {
137a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu            fgCall = fg;
138a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu            ringing = ring;
139a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu        }
140a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu    }
141a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu
1427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
1437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Handler that tracks the connections and updates the value of the
1447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Mute settings for each connection as needed.
1457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
1467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static class ConnectionHandler extends Handler {
1477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        @Override
1487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        public void handleMessage(Message msg) {
1497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            switch (msg.what) {
150a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                case MSG_CHECK_STATUS_ANSWERCALL:
151a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                    FgRingCalls frC = (FgRingCalls) msg.obj;
152a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                    // wait for finishing disconnecting
153a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                    // before check the ringing call state
154a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                    if ((frC.fgCall != null) &&
155a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                        (frC.fgCall.getState() == Call.State.DISCONNECTING) &&
156a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                        (msg.arg1 < DISCONNECTING_POLLING_TIMES_LIMIT)) {
157a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                        Message retryMsg =
158a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                            mConnectionHandler.obtainMessage(MSG_CHECK_STATUS_ANSWERCALL);
159a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                        retryMsg.arg1 = 1 + msg.arg1;
160a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                        retryMsg.obj = msg.obj;
161a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                        mConnectionHandler.sendMessageDelayed(retryMsg,
162a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                            DISCONNECTING_POLLING_INTERVAL_MS);
163a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                    // since hangupActiveCall() also accepts the ringing call
164a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                    // check if the ringing call was already answered or not
165a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                    // only answer it when the call still is ringing
166a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                    } else if (frC.ringing.isRinging()) {
167a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                        if (msg.arg1 == DISCONNECTING_POLLING_TIMES_LIMIT) {
168a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                            Log.e(LOG_TAG, "DISCONNECTING time out");
169a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                        }
170a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                        answerCall(frC.ringing);
171a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                    }
172a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                    break;
1737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                case PHONE_STATE_CHANGED:
174a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                    AsyncResult ar = (AsyncResult) msg.obj;
1757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    if (DBG) log("ConnectionHandler: updating mute state for each connection");
1767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    CallManager cm = (CallManager) ar.userObj;
1787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // update the foreground connections, if there are new connections.
1807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // Have to get all foreground calls instead of the active one
1817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // because there may two foreground calls co-exist in shore period
1827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // (a racing condition based on which phone changes firstly)
1837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // Otherwise the connection may get deleted.
1847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    List<Connection> fgConnections = new ArrayList<Connection>();
1857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    for (Call fgCall : cm.getForegroundCalls()) {
1867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        if (!fgCall.isIdle()) {
1877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            fgConnections.addAll(fgCall.getConnections());
1887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        }
1897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    }
1907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    for (Connection cn : fgConnections) {
1917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        if (sConnectionMuteTable.get(cn) == null) {
1927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            sConnectionMuteTable.put(cn, Boolean.FALSE);
1937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        }
1947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    }
1957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // mute is connection based operation, we need loop over
1977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // all background calls instead of the first one to update
1987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // the background connections, if there are new connections.
1997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    List<Connection> bgConnections = new ArrayList<Connection>();
2007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    for (Call bgCall : cm.getBackgroundCalls()) {
2017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        if (!bgCall.isIdle()) {
2027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            bgConnections.addAll(bgCall.getConnections());
2037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        }
2047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    }
2057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    for (Connection cn : bgConnections) {
2067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        if (sConnectionMuteTable.get(cn) == null) {
2077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                          sConnectionMuteTable.put(cn, Boolean.FALSE);
2087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        }
2097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    }
2107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // Check to see if there are any lingering connections here
2127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // (disconnected connections), use old-school iterators to avoid
2137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // concurrent modification exceptions.
2147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    Connection cn;
2157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    for (Iterator<Connection> cnlist = sConnectionMuteTable.keySet().iterator();
2167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            cnlist.hasNext();) {
2177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        cn = cnlist.next();
2187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        if (!fgConnections.contains(cn) && !bgConnections.contains(cn)) {
2197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            if (DBG) log("connection '" + cn + "' not accounted for, removing.");
2207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            cnlist.remove();
2217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        }
2227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    }
2237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // Restore the mute state of the foreground call if we're not IDLE,
2257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // otherwise just clear the mute state. This is really saying that
2267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // as long as there is one or more connections, we should update
2277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // the mute state with the earliest connection on the foreground
2287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // call, and that with no connections, we should be back to a
2297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // non-mute state.
2307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    if (cm.getState() != PhoneConstants.State.IDLE) {
2317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        restoreMuteState();
2327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    } else {
2337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        setMuteInternal(cm.getFgPhone(), false);
2347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    }
2357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    break;
2377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
2387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
2397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
2407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
2427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Register the ConnectionHandler with the phone, to receive connection events
2437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
2447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public static void initializeConnectionHandler(CallManager cm) {
2457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (mConnectionHandler == null) {
2467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            mConnectionHandler = new ConnectionHandler();
2477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
2487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // pass over cm as user.obj
2507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        cm.registerForPreciseCallStateChanged(mConnectionHandler, PHONE_STATE_CHANGED, cm);
2517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
2537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /** This class is never instantiated. */
2557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private PhoneUtils() {
2567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
2577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
2597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Answer the currently-ringing call.
2607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
2617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return true if we answered the call, or false if there wasn't
2627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *         actually a ringing incoming call, or some other error occurred.
2637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
2647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @see #answerAndEndHolding(CallManager, Call)
2657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @see #answerAndEndActive(CallManager, Call)
2667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
2677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /* package */ static boolean answerCall(Call ringingCall) {
2687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        log("answerCall(" + ringingCall + ")...");
2697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final PhoneGlobals app = PhoneGlobals.getInstance();
2707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final CallNotifier notifier = app.notifier;
2717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // If the ringer is currently ringing and/or vibrating, stop it
2737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // right now (before actually answering the call.)
2747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        notifier.silenceRinger();
2757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final Phone phone = ringingCall.getPhone();
2777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final boolean phoneIsCdma = (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA);
2787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        boolean answered = false;
2797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        IBluetoothHeadsetPhone btPhone = null;
2807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (phoneIsCdma) {
2827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // Stop any signalInfo tone being played when a Call waiting gets answered
2837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (ringingCall.getState() == Call.State.WAITING) {
2847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                notifier.stopSignalInfoTone();
2857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
2867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
2877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (ringingCall != null && ringingCall.isRinging()) {
2897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG) log("answerCall: call state = " + ringingCall.getState());
2907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            try {
2917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (phoneIsCdma) {
2927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    if (app.cdmaPhoneCallState.getCurrentCallState()
2937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            == CdmaPhoneCallState.PhoneCallState.IDLE) {
2947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        // This is the FIRST incoming call being answered.
2957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        // Set the Phone Call State to SINGLE_ACTIVE
2967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        app.cdmaPhoneCallState.setCurrentCallState(
2977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                CdmaPhoneCallState.PhoneCallState.SINGLE_ACTIVE);
2987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    } else {
2997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        // This is the CALL WAITING call being answered.
3007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        // Set the Phone Call State to CONF_CALL
3017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        app.cdmaPhoneCallState.setCurrentCallState(
3027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                CdmaPhoneCallState.PhoneCallState.CONF_CALL);
3037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        // Enable "Add Call" option after answering a Call Waiting as the user
3047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        // should be allowed to add another call in case one of the parties
3057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        // drops off
3067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        app.cdmaPhoneCallState.setAddCallMenuStateAfterCallWaiting(true);
3077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
3087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        // If a BluetoothPhoneService is valid we need to set the second call state
3097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        // so that the Bluetooth client can update the Call state correctly when
3107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        // a call waiting is answered from the Phone.
3117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        btPhone = app.getBluetoothPhoneService();
3127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        if (btPhone != null) {
3137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            try {
3147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                btPhone.cdmaSetSecondCallState(true);
3157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            } catch (RemoteException e) {
3167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                Log.e(LOG_TAG, Log.getStackTraceString(new Throwable()));
3177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            }
3187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        }
3197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                  }
3207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
3217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
3227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                final boolean isRealIncomingCall = isRealIncomingCall(ringingCall.getState());
3237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
3247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //if (DBG) log("sPhone.acceptCall");
3257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                app.mCM.acceptCall(ringingCall);
3267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                answered = true;
3277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
3287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // Always reset to "unmuted" for a freshly-answered call
3297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                setMute(false);
3307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
3317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                setAudioMode();
3327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
3337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // Check is phone in any dock, and turn on speaker accordingly
3347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                final boolean speakerActivated = activateSpeakerIfDocked(phone);
3357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
33627a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon                final BluetoothManager btManager = app.getBluetoothManager();
33727a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon
3387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // When answering a phone call, the user will move the phone near to her/his ear
3397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // and start conversation, without checking its speaker status. If some other
3407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // application turned on the speaker mode before the call and didn't turn it off,
3417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // Phone app would need to be responsible for the speaker phone.
3427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // Here, we turn off the speaker if
3437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // - the phone call is the first in-coming call,
3447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // - we did not activate speaker by ourselves during the process above, and
3457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // - Bluetooth headset is not in use.
3467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (isRealIncomingCall && !speakerActivated && isSpeakerOn(app)
34727a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon                        && !btManager.isBluetoothHeadsetAudioOn()) {
3487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // This is not an error but might cause users' confusion. Add log just in case.
3497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    Log.i(LOG_TAG, "Forcing speaker off due to new incoming call...");
3507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    turnOnSpeaker(app, false, true);
3517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
3527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            } catch (CallStateException ex) {
3537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Log.w(LOG_TAG, "answerCall: caught " + ex, ex);
3547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
3557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (phoneIsCdma) {
3567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // restore the cdmaPhoneCallState and btPhone.cdmaSetSecondCallState:
3577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    app.cdmaPhoneCallState.setCurrentCallState(
3587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            app.cdmaPhoneCallState.getPreviousCallState());
3597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    if (btPhone != null) {
3607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        try {
3617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            btPhone.cdmaSetSecondCallState(false);
3627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        } catch (RemoteException e) {
3637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            Log.e(LOG_TAG, Log.getStackTraceString(new Throwable()));
3647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        }
3657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    }
3667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
3677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
3687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
3697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return answered;
3707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
3717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
3727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
373de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon     * Hangs up all active calls.
374de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon     */
375de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon    static void hangupAllCalls(CallManager cm) {
376de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon        final Call ringing = cm.getFirstActiveRingingCall();
377de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon        final Call fg = cm.getActiveFgCall();
378de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon        final Call bg = cm.getFirstActiveBgCall();
379de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon
380de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon        // We go in reverse order, BG->FG->RINGING because hanging up a ringing call or an active
381de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon        // call can move a bg call to a fg call which would force us to loop over each call
382de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon        // several times.  This ordering works best to ensure we dont have any more calls.
383de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon        if (bg != null && !bg.isIdle()) {
384de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon            hangup(bg);
385de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon        }
386de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon        if (fg != null && !fg.isIdle()) {
387de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon            hangup(fg);
388de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon        }
389de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon        if (ringing != null && !ringing.isIdle()) {
390de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon            hangupRingingCall(fg);
391de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon        }
392de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon    }
393de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon
394de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon    /**
3957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Smart "hang up" helper method which hangs up exactly one connection,
3967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * based on the current Phone state, as follows:
3977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * <ul>
3987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * <li>If there's a ringing call, hang that up.
3997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * <li>Else if there's a foreground call, hang that up.
4007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * <li>Else if there's a background call, hang that up.
4017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * <li>Otherwise do nothing.
4027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * </ul>
4037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return true if we successfully hung up, or false
4047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *              if there were no active calls at all.
4057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
4067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static boolean hangup(CallManager cm) {
4077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        boolean hungup = false;
4087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Call ringing = cm.getFirstActiveRingingCall();
4097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Call fg = cm.getActiveFgCall();
4107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Call bg = cm.getFirstActiveBgCall();
4117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (!ringing.isIdle()) {
4137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            log("hangup(): hanging up ringing call");
4147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            hungup = hangupRingingCall(ringing);
4157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else if (!fg.isIdle()) {
4167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            log("hangup(): hanging up foreground call");
4177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            hungup = hangup(fg);
4187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else if (!bg.isIdle()) {
4197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            log("hangup(): hanging up background call");
4207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            hungup = hangup(bg);
4217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
4227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // No call to hang up!  This is unlikely in normal usage,
4237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // since the UI shouldn't be providing an "End call" button in
4247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // the first place.  (But it *can* happen, rarely, if an
4257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // active call happens to disconnect on its own right when the
4267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // user is trying to hang up..)
4277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            log("hangup(): no active call to hang up");
4287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
4297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("==> hungup = " + hungup);
4307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return hungup;
4327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
4337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static boolean hangupRingingCall(Call ringing) {
4357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("hangup ringing call");
4367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        int phoneType = ringing.getPhone().getPhoneType();
4377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Call.State state = ringing.getState();
4387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (state == Call.State.INCOMING) {
4407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // Regular incoming call (with no other active calls)
4417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            log("hangupRingingCall(): regular incoming call: hangup()");
4427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return hangup(ringing);
4437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else if (state == Call.State.WAITING) {
4447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // Call-waiting: there's an incoming call, but another call is
4457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // already active.
4467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // TODO: It would be better for the telephony layer to provide
4477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // a "hangupWaitingCall()" API that works on all devices,
4487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // rather than us having to check the phone type here and do
4497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // the notifier.sendCdmaCallWaitingReject() hack for CDMA phones.
4507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
4517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // CDMA: Ringing call and Call waiting hangup is handled differently.
4527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // For Call waiting we DO NOT call the conventional hangup(call) function
4537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // as in CDMA we just want to hangup the Call waiting connection.
4547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                log("hangupRingingCall(): CDMA-specific call-waiting hangup");
4557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                final CallNotifier notifier = PhoneGlobals.getInstance().notifier;
4567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                notifier.sendCdmaCallWaitingReject();
4577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                return true;
4587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            } else {
4597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // Otherwise, the regular hangup() API works for
4607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // call-waiting calls too.
4617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                log("hangupRingingCall(): call-waiting call: hangup()");
4627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                return hangup(ringing);
4637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
4647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
4657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // Unexpected state: the ringing call isn't INCOMING or
4667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // WAITING, so there's no reason to have called
4677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // hangupRingingCall() in the first place.
4687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // (Presumably the incoming call went away at the exact moment
4697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // we got here, so just do nothing.)
4707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Log.w(LOG_TAG, "hangupRingingCall: no INCOMING or WAITING call");
4717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return false;
4727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
4737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
4747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static boolean hangupActiveCall(Call foreground) {
4767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("hangup active call");
4777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return hangup(foreground);
4787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
4797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static boolean hangupHoldingCall(Call background) {
4817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("hangup holding call");
4827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return hangup(background);
4837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
4847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
4867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Used in CDMA phones to end the complete Call session
4877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param phone the Phone object.
4887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return true if *any* call was successfully hung up
4897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
4907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static boolean hangupRingingAndActive(Phone phone) {
4917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        boolean hungUpRingingCall = false;
4927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        boolean hungUpFgCall = false;
4937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Call ringingCall = phone.getRingingCall();
4947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Call fgCall = phone.getForegroundCall();
4957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Hang up any Ringing Call
4977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (!ringingCall.isIdle()) {
4987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            log("hangupRingingAndActive: Hang up Ringing Call");
4997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            hungUpRingingCall = hangupRingingCall(ringingCall);
5007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
5017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Hang up any Active Call
5037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (!fgCall.isIdle()) {
5047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            log("hangupRingingAndActive: Hang up Foreground Call");
5057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            hungUpFgCall = hangupActiveCall(fgCall);
5067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
5077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return hungUpRingingCall || hungUpFgCall;
5097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
5107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
5127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Trivial wrapper around Call.hangup(), except that we return a
5137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * boolean success code rather than throwing CallStateException on
5147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * failure.
5157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
5167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return true if the call was successfully hung up, or false
5177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *         if the call wasn't actually active.
5187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
5197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static boolean hangup(Call call) {
5207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        try {
5217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            CallManager cm = PhoneGlobals.getInstance().mCM;
5227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (call.getState() == Call.State.ACTIVE && cm.hasActiveBgCall()) {
5247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // handle foreground call hangup while there is background call
5257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                log("- hangup(Call): hangupForegroundResumeBackground...");
5267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                cm.hangupForegroundResumeBackground(cm.getFirstActiveBgCall());
5277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            } else {
5287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                log("- hangup(Call): regular hangup()...");
5297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                call.hangup();
5307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
5317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return true;
5327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } catch (CallStateException ex) {
5337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Log.e(LOG_TAG, "Call hangup: caught " + ex, ex);
5347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
5357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return false;
5377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
5387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
5407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Trivial wrapper around Connection.hangup(), except that we silently
5417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * do nothing (rather than throwing CallStateException) if the
5427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * connection wasn't actually active.
5437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
5447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static void hangup(Connection c) {
5457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        try {
5467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (c != null) {
5477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                c.hangup();
5487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
5497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } catch (CallStateException ex) {
5507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Log.w(LOG_TAG, "Connection hangup: caught " + ex, ex);
5517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
5527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
5537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static boolean answerAndEndHolding(CallManager cm, Call ringing) {
5557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("end holding & answer waiting: 1");
5567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (!hangupHoldingCall(cm.getFirstActiveBgCall())) {
5577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Log.e(LOG_TAG, "end holding failed!");
5587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return false;
5597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
5607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("end holding & answer waiting: 2");
5627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return answerCall(ringing);
5637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
5657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
5677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Answers the incoming call specified by "ringing", and ends the currently active phone call.
5687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
5697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * This method is useful when's there's an incoming call which we cannot manage with the
5707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * current call. e.g. when you are having a phone call with CDMA network and has received
5717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * a SIP call, then we won't expect our telephony can manage those phone calls simultaneously.
5727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Note that some types of network may allow multiple phone calls at once; GSM allows to hold
5737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * an ongoing phone call, so we don't need to end the active call. The caller of this method
5747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * needs to check if the network allows multiple phone calls or not.
5757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
5767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @see #answerCall(Call)
5777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @see InCallScreen#internalAnswerCall()
5787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
5797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /* package */ static boolean answerAndEndActive(CallManager cm, Call ringing) {
5807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("answerAndEndActive()...");
5817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Unlike the answerCall() method, we *don't* need to stop the
5837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // ringer or change audio modes here since the user is already
5847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // in-call, which means that the audio mode is already set
5857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // correctly, and that we wouldn't have started the ringer in the
5867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // first place.
5877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // hanging up the active call also accepts the waiting call
5897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // while active call and waiting call are from the same phone
5907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // i.e. both from GSM phone
591a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu        Call fgCall = cm.getActiveFgCall();
592a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu        if (!hangupActiveCall(fgCall)) {
5937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Log.w(LOG_TAG, "end active call failed!");
5947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return false;
5957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
5967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
597a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu        mConnectionHandler.removeMessages(MSG_CHECK_STATUS_ANSWERCALL);
598a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu        Message msg = mConnectionHandler.obtainMessage(MSG_CHECK_STATUS_ANSWERCALL);
599a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu        msg.arg1 = 1;
600a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu        msg.obj = new FgRingCalls(fgCall, ringing);
601a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu        mConnectionHandler.sendMessage(msg);
6027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
6037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return true;
6047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
6057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
6067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
6077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * For a CDMA phone, advance the call state upon making a new
6087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * outgoing call.
6097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
6107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * <pre>
6117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *   IDLE -> SINGLE_ACTIVE
6127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * or
6137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *   SINGLE_ACTIVE -> THRWAY_ACTIVE
6147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * </pre>
6157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param app The phone instance.
6167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
617ad1ed6d23c4a999a41bb73b8243009e32f96d7dfSantos Cordon    private static void updateCdmaCallStateOnNewOutgoingCall(PhoneGlobals app,
618ad1ed6d23c4a999a41bb73b8243009e32f96d7dfSantos Cordon            Connection connection) {
6197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (app.cdmaPhoneCallState.getCurrentCallState() ==
6207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            CdmaPhoneCallState.PhoneCallState.IDLE) {
6217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // This is the first outgoing call. Set the Phone Call State to ACTIVE
6227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            app.cdmaPhoneCallState.setCurrentCallState(
6237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                CdmaPhoneCallState.PhoneCallState.SINGLE_ACTIVE);
6247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
6257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // This is the second outgoing call. Set the Phone Call State to 3WAY
6267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            app.cdmaPhoneCallState.setCurrentCallState(
6277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE);
628ad1ed6d23c4a999a41bb73b8243009e32f96d7dfSantos Cordon
629ad1ed6d23c4a999a41bb73b8243009e32f96d7dfSantos Cordon            app.getCallModeler().setCdmaOutgoing3WayCall(connection);
6307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
6317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
6327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
6337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
63469a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon     * @see placeCall below
63569a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon     */
63669a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon    public static int placeCall(Context context, Phone phone, String number, Uri contactRef,
63769a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon            boolean isEmergencyCall) {
63869a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon        return placeCall(context, phone, number, contactRef, isEmergencyCall,
63969a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon                CallGatewayManager.EMPTY_INFO, null);
64069a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon    }
64169a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon
64269a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon    /**
6437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Dial the number using the phone passed in.
6447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
6457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * If the connection is establised, this method issues a sync call
6467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * that may block to query the caller info.
6477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * TODO: Change the logic to use the async query.
6487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
6497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param context To perform the CallerInfo query.
6507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param phone the Phone object.
6517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param number to be dialed as requested by the user. This is
6527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * NOT the phone number to connect to. It is used only to build the
6537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * call card and to update the call log. See above for restrictions.
6547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param contactRef that triggered the call. Typically a 'tel:'
6557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * uri but can also be a 'content://contacts' one.
6567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param isEmergencyCall indicates that whether or not this is an
6577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * emergency call
6587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param gatewayUri Is the address used to setup the connection, null
6597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * if not using a gateway
66069a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon     * @param callGateway Class for setting gateway data on a successful call.
6617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
6627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return either CALL_STATUS_DIALED or CALL_STATUS_FAILED
6637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
66469a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon    public static int placeCall(Context context, Phone phone, String number, Uri contactRef,
66569a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon            boolean isEmergencyCall, RawGatewayInfo gatewayInfo, CallGatewayManager callGateway) {
66669a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon        final Uri gatewayUri = gatewayInfo.gatewayUri;
66769a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon
6687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (VDBG) {
6697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            log("placeCall()... number: '" + number + "'"
6707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    + ", GW:'" + gatewayUri + "'"
6717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    + ", contactRef:" + contactRef
6727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    + ", isEmergencyCall: " + isEmergencyCall);
6737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
6747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            log("placeCall()... number: " + toLogSafePhoneNumber(number)
6757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    + ", GW: " + (gatewayUri != null ? "non-null" : "null")
6767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    + ", emergency? " + isEmergencyCall);
6777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
6787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final PhoneGlobals app = PhoneGlobals.getInstance();
6797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
6807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        boolean useGateway = false;
6817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (null != gatewayUri &&
6827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            !isEmergencyCall &&
6837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            PhoneUtils.isRoutableViaGateway(number)) {  // Filter out MMI, OTA and other codes.
6847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            useGateway = true;
6857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
6867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
6877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        int status = CALL_STATUS_DIALED;
6887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Connection connection;
6897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        String numberToDial;
6907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (useGateway) {
6917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // TODO: 'tel' should be a constant defined in framework base
6927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // somewhere (it is in webkit.)
6937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (null == gatewayUri || !Constants.SCHEME_TEL.equals(gatewayUri.getScheme())) {
6947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Log.e(LOG_TAG, "Unsupported URL:" + gatewayUri);
6957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                return CALL_STATUS_FAILED;
6967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
6977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
6987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // We can use getSchemeSpecificPart because we don't allow #
6997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // in the gateway numbers (treated a fragment delim.) However
7007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // if we allow more complex gateway numbers sequence (with
7017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // passwords or whatnot) that use #, this may break.
7027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // TODO: Need to support MMI codes.
7037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            numberToDial = gatewayUri.getSchemeSpecificPart();
7047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
7057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            numberToDial = number;
7067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
7077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
7087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Remember if the phone state was in IDLE state before this call.
7097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // After calling CallManager#dial(), getState() will return different state.
7107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final boolean initiallyIdle = app.mCM.getState() == PhoneConstants.State.IDLE;
7117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
7127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        try {
7137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            connection = app.mCM.dial(phone, numberToDial);
7147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } catch (CallStateException ex) {
7157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // CallStateException means a new outgoing call is not currently
7167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // possible: either no more call slots exist, or there's another
7177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // call already in the process of dialing or ringing.
7187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Log.w(LOG_TAG, "Exception from app.mCM.dial()", ex);
7197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return CALL_STATUS_FAILED;
7207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
7217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // Note that it's possible for CallManager.dial() to return
7227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // null *without* throwing an exception; that indicates that
7237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // we dialed an MMI (see below).
7247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
7257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
72669a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon        // Now that the call is successful, we can save the gateway info for the call
72769a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon        if (callGateway != null) {
72869a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon            callGateway.setGatewayInfoForConnection(connection, gatewayInfo);
72969a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon        }
73069a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon
7317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        int phoneType = phone.getPhoneType();
7327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
7337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // On GSM phones, null is returned for MMI codes
7347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (null == connection) {
7357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (phoneType == PhoneConstants.PHONE_TYPE_GSM && gatewayUri == null) {
7367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (DBG) log("dialed MMI code: " + number);
7377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                status = CALL_STATUS_DIALED_MMI;
7387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            } else {
7397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                status = CALL_STATUS_FAILED;
7407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
7417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
7427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
743ad1ed6d23c4a999a41bb73b8243009e32f96d7dfSantos Cordon                updateCdmaCallStateOnNewOutgoingCall(app, connection);
7447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
7457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
7467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (gatewayUri == null) {
7477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // phone.dial() succeeded: we're now in a normal phone call.
7487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // attach the URI to the CallerInfo Object if it is there,
7497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // otherwise just attach the Uri Reference.
7507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // if the uri does not have a "content" scheme, then we treat
7517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // it as if it does NOT have a unique reference.
7527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                String content = context.getContentResolver().SCHEME_CONTENT;
7537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if ((contactRef != null) && (contactRef.getScheme().equals(content))) {
7547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    Object userDataObject = connection.getUserData();
7557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    if (userDataObject == null) {
7567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        connection.setUserData(contactRef);
7577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    } else {
7587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        // TODO: This branch is dead code, we have
7597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        // just created the connection which has
7607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        // no user data (null) by default.
7617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        if (userDataObject instanceof CallerInfo) {
7627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        ((CallerInfo) userDataObject).contactRefUri = contactRef;
7637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        } else {
7647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        ((CallerInfoToken) userDataObject).currentInfo.contactRefUri =
7657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            contactRef;
7667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        }
7677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    }
7687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
7697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
770c264cba0b6ea81b3f741d9c41a0a50b7ffd19220Santos Cordon
771e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng            startGetCallerInfo(context, connection, null, null, gatewayInfo);
772e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng
773c264cba0b6ea81b3f741d9c41a0a50b7ffd19220Santos Cordon            // Always set mute to off when we are dialing an emergency number
774c264cba0b6ea81b3f741d9c41a0a50b7ffd19220Santos Cordon            if (isEmergencyCall) {
775c264cba0b6ea81b3f741d9c41a0a50b7ffd19220Santos Cordon                setMute(false);
776c264cba0b6ea81b3f741d9c41a0a50b7ffd19220Santos Cordon            }
777c264cba0b6ea81b3f741d9c41a0a50b7ffd19220Santos Cordon
7787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            setAudioMode();
7797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
7807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG) log("about to activate speaker");
7817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // Check is phone in any dock, and turn on speaker accordingly
7827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            final boolean speakerActivated = activateSpeakerIfDocked(phone);
7837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
78427a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon            final BluetoothManager btManager = app.getBluetoothManager();
78527a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon
7867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // See also similar logic in answerCall().
7877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (initiallyIdle && !speakerActivated && isSpeakerOn(app)
78827a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon                    && !btManager.isBluetoothHeadsetAudioOn()) {
7897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // This is not an error but might cause users' confusion. Add log just in case.
7907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Log.i(LOG_TAG, "Forcing speaker off when initiating a new outgoing call...");
7917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                PhoneUtils.turnOnSpeaker(app, false, true);
7927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
7937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
7947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
7957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return status;
7967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
7977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
7987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /* package */ static String toLogSafePhoneNumber(String number) {
7997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // For unknown number, log empty string.
8007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (number == null) {
8017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return "";
8027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
8037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
8047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (VDBG) {
8057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // When VDBG is true we emit PII.
8067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return number;
8077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
8087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
8097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Do exactly same thing as Uri#toSafeString() does, which will enable us to compare
8107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // sanitized phone numbers.
8117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        StringBuilder builder = new StringBuilder();
8127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        for (int i = 0; i < number.length(); i++) {
8137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            char c = number.charAt(i);
8147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (c == '-' || c == '@' || c == '.') {
8157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                builder.append(c);
8167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            } else {
8177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                builder.append('x');
8187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
8197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
8207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return builder.toString();
8217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
8227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
8237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
8247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Wrapper function to control when to send an empty Flash command to the network.
8257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Mainly needed for CDMA networks, such as scenarios when we need to send a blank flash
8267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * to the network prior to placing a 3-way call for it to be successful.
8277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
8287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static void sendEmptyFlash(Phone phone) {
8297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {
8307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Call fgCall = phone.getForegroundCall();
8317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (fgCall.getState() == Call.State.ACTIVE) {
8327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // Send the empty flash
8337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (DBG) Log.d(LOG_TAG, "onReceive: (CDMA) sending empty flash to network");
8347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                switchHoldingAndActive(phone.getBackgroundCall());
8357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
8367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
8377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
8387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
8397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
8407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param heldCall is the background call want to be swapped
8417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
8427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static void switchHoldingAndActive(Call heldCall) {
8437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        log("switchHoldingAndActive()...");
8447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        try {
8457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            CallManager cm = PhoneGlobals.getInstance().mCM;
8467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (heldCall.isIdle()) {
8477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // no heldCall, so it is to hold active call
8487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                cm.switchHoldingAndActive(cm.getFgPhone().getBackgroundCall());
8497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            } else {
8507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // has particular heldCall, so to switch
8517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                cm.switchHoldingAndActive(heldCall);
8527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
8537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            setAudioMode(cm);
8547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } catch (CallStateException ex) {
8557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Log.w(LOG_TAG, "switchHoldingAndActive: caught " + ex, ex);
8567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
8577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
8587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
8597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
8607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Restore the mute setting from the earliest connection of the
8617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * foreground call.
8627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
8637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static Boolean restoreMuteState() {
8647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Phone phone = PhoneGlobals.getInstance().mCM.getFgPhone();
8657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
8667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //get the earliest connection
8677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Connection c = phone.getForegroundCall().getEarliestConnection();
8687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
8697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // only do this if connection is not null.
8707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (c != null) {
8717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
8727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            int phoneType = phone.getPhoneType();
8737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
8747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // retrieve the mute value.
8757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Boolean shouldMute = null;
8767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
8777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // In CDMA, mute is not maintained per Connection. Single mute apply for
8787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // a call where  call can have multiple connections such as
8797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // Three way and Call Waiting.  Therefore retrieving Mute state for
8807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // latest connection can apply for all connection in that call
8817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
8827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                shouldMute = sConnectionMuteTable.get(
8837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        phone.getForegroundCall().getLatestConnection());
8847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            } else if ((phoneType == PhoneConstants.PHONE_TYPE_GSM)
885bd76e4e0407f75c4e6a6961cf943d36fc75a0e1aSailesh Nepal                    || (phoneType == PhoneConstants.PHONE_TYPE_SIP)
886bd76e4e0407f75c4e6a6961cf943d36fc75a0e1aSailesh Nepal                    || (phoneType == PhoneConstants.PHONE_TYPE_THIRD_PARTY)) {
8877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                shouldMute = sConnectionMuteTable.get(c);
8887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
8897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (shouldMute == null) {
8907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (DBG) log("problem retrieving mute value for this connection.");
8917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                shouldMute = Boolean.FALSE;
8927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
8937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
8947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // set the mute value and return the result.
8957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            setMute (shouldMute.booleanValue());
8967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return shouldMute;
8977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
8987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return Boolean.valueOf(getMute());
8997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
9007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
9017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static void mergeCalls() {
9027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        mergeCalls(PhoneGlobals.getInstance().mCM);
9037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
9047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
9057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static void mergeCalls(CallManager cm) {
9067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        int phoneType = cm.getFgPhone().getPhoneType();
9077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
9087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            log("mergeCalls(): CDMA...");
9097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            PhoneGlobals app = PhoneGlobals.getInstance();
9107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (app.cdmaPhoneCallState.getCurrentCallState()
9117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    == CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE) {
9127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // Set the Phone Call State to conference
9137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                app.cdmaPhoneCallState.setCurrentCallState(
9147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        CdmaPhoneCallState.PhoneCallState.CONF_CALL);
9157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
9167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // Send flash cmd
9177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // TODO: Need to change the call from switchHoldingAndActive to
9187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // something meaningful as we are not actually trying to swap calls but
9197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // instead are merging two calls by sending a Flash command.
9207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                log("- sending flash...");
9217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                switchHoldingAndActive(cm.getFirstActiveBgCall());
9227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
9237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
9247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            try {
9257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                log("mergeCalls(): calling cm.conference()...");
9267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                cm.conference(cm.getFirstActiveBgCall());
9277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            } catch (CallStateException ex) {
9287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Log.w(LOG_TAG, "mergeCalls: caught " + ex, ex);
9297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
9307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
9317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
9327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
9337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static void separateCall(Connection c) {
9347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        try {
9357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG) log("separateCall: " + toLogSafePhoneNumber(c.getAddress()));
9367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            c.separate();
9377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } catch (CallStateException ex) {
9387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Log.w(LOG_TAG, "separateCall: caught " + ex, ex);
9397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
9407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
9417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
9427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
9437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Handle the MMIInitiate message and put up an alert that lets
9447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * the user cancel the operation, if applicable.
9457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
9467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param context context to get strings.
9477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param mmiCode the MmiCode object being started.
9487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param buttonCallbackMessage message to post when button is clicked.
9497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param previousAlert a previous alert used in this activity.
9507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return the dialog handle
9517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
9527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static Dialog displayMMIInitiate(Context context,
9537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                          MmiCode mmiCode,
9547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                          Message buttonCallbackMessage,
9557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                          Dialog previousAlert) {
9567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("displayMMIInitiate: " + mmiCode);
9577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (previousAlert != null) {
9587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            previousAlert.dismiss();
9597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
9607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
9617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // The UI paradigm we are using now requests that all dialogs have
9627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // user interaction, and that any other messages to the user should
9637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // be by way of Toasts.
9647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //
9657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // In adhering to this request, all MMI initiating "OK" dialogs
9667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // (non-cancelable MMIs) that end up being closed when the MMI
9677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // completes (thereby showing a completion dialog) are being
9687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // replaced with Toasts.
9697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //
9707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // As a side effect, moving to Toasts for the non-cancelable MMIs
9717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // also means that buttonCallbackMessage (which was tied into "OK")
9727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // is no longer invokable for these dialogs.  This is not a problem
9737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // since the only callback messages we supported were for cancelable
9747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // MMIs anyway.
9757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //
9767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // A cancelable MMI is really just a USSD request. The term
9777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // "cancelable" here means that we can cancel the request when the
9787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // system prompts us for a response, NOT while the network is
9797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // processing the MMI request.  Any request to cancel a USSD while
9807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // the network is NOT ready for a response may be ignored.
9817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //
9827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // With this in mind, we replace the cancelable alert dialog with
9837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // a progress dialog, displayed until we receive a request from
9847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // the the network.  For more information, please see the comments
9857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // in the displayMMIComplete() method below.
9867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //
9877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Anything that is NOT a USSD request is a normal MMI request,
9887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // which will bring up a toast (desribed above).
9897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
9907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        boolean isCancelable = (mmiCode != null) && mmiCode.isCancelable();
9917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
9927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (!isCancelable) {
9937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG) log("not a USSD code, displaying status toast.");
9947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            CharSequence text = context.getText(R.string.mmiStarted);
9957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Toast.makeText(context, text, Toast.LENGTH_SHORT)
9967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                .show();
9977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return null;
9987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
9997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG) log("running USSD code, displaying indeterminate progress.");
10007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
10017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // create the indeterminate progress dialog and display it.
10027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            ProgressDialog pd = new ProgressDialog(context);
10037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            pd.setMessage(context.getText(R.string.ussdRunning));
10047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            pd.setCancelable(false);
10057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            pd.setIndeterminate(true);
10067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            pd.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
10077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
10087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            pd.show();
10097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
10107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return pd;
10117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
10127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
10137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
10147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
10157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
10167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Handle the MMIComplete message and fire off an intent to display
10177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * the message.
10187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
10197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param context context to get strings.
10207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param mmiCode MMI result.
10217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param previousAlert a previous alert used in this activity.
10227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
10237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static void displayMMIComplete(final Phone phone, Context context, final MmiCode mmiCode,
10247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Message dismissCallbackMessage,
10257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            AlertDialog previousAlert) {
10267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final PhoneGlobals app = PhoneGlobals.getInstance();
10277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        CharSequence text;
10287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        int title = 0;  // title for the progress dialog, if needed.
10297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        MmiCode.State state = mmiCode.getState();
10307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
10317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("displayMMIComplete: state=" + state);
10327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
10337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        switch (state) {
10347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            case PENDING:
10357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // USSD code asking for feedback from user.
10367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                text = mmiCode.getMessage();
10377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (DBG) log("- using text from PENDING MMI message: '" + text + "'");
10387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                break;
10397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            case CANCELLED:
10407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                text = null;
10417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                break;
10427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            case COMPLETE:
10437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (app.getPUKEntryActivity() != null) {
10447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // if an attempt to unPUK the device was made, we specify
10457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // the title and the message here.
10467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    title = com.android.internal.R.string.PinMmi;
10477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    text = context.getText(R.string.puk_unlocked);
10487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    break;
10497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
10507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // All other conditions for the COMPLETE mmi state will cause
10517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // the case to fall through to message logic in common with
10527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // the FAILED case.
10537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
10547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            case FAILED:
10557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                text = mmiCode.getMessage();
10567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (DBG) log("- using text from MMI message: '" + text + "'");
10577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                break;
10587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            default:
10597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                throw new IllegalStateException("Unexpected MmiCode state: " + state);
10607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
10617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
10627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (previousAlert != null) {
10637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            previousAlert.dismiss();
10647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
10657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
10667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Check to see if a UI exists for the PUK activation.  If it does
10677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // exist, then it indicates that we're trying to unblock the PUK.
10687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if ((app.getPUKEntryActivity() != null) && (state == MmiCode.State.COMPLETE)) {
10697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG) log("displaying PUK unblocking progress dialog.");
10707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
10717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // create the progress dialog, make sure the flags and type are
10727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // set correctly.
10737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            ProgressDialog pd = new ProgressDialog(app);
10747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            pd.setTitle(title);
10757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            pd.setMessage(text);
10767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            pd.setCancelable(false);
10777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            pd.setIndeterminate(true);
10787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            pd.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
10797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            pd.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
10807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
10817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // display the dialog
10827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            pd.show();
10837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
10847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // indicate to the Phone app that the progress dialog has
10857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // been assigned for the PUK unlock / SIM READY process.
10867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            app.setPukEntryProgressDialog(pd);
10877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
10887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
10897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // In case of failure to unlock, we'll need to reset the
10907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // PUK unlock activity, so that the user may try again.
10917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (app.getPUKEntryActivity() != null) {
10927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                app.setPukEntryActivity(null);
10937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
10947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
10957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // A USSD in a pending state means that it is still
10967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // interacting with the user.
10977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (state != MmiCode.State.PENDING) {
10987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (DBG) log("MMI code has finished running.");
10997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
11007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (DBG) log("Extended NW displayMMIInitiate (" + text + ")");
11017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (text == null || text.length() == 0)
11027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    return;
11037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
11047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // displaying system alert dialog on the screen instead of
11057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // using another activity to display the message.  This
11067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // places the message at the forefront of the UI.
11077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                AlertDialog newDialog = new AlertDialog.Builder(context)
11087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        .setMessage(text)
11097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        .setPositiveButton(R.string.ok, null)
11107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        .setCancelable(true)
11117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        .create();
11127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
11137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                newDialog.getWindow().setType(
11147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
11157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                newDialog.getWindow().addFlags(
11167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        WindowManager.LayoutParams.FLAG_DIM_BEHIND);
11177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
11187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                newDialog.show();
11197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            } else {
11207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (DBG) log("USSD code has requested user input. Constructing input dialog.");
11217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
11227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // USSD MMI code that is interacting with the user.  The
11237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // basic set of steps is this:
11247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //   1. User enters a USSD request
11257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //   2. We recognize the request and displayMMIInitiate
11267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //      (above) creates a progress dialog.
11277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //   3. Request returns and we get a PENDING or COMPLETE
11287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //      message.
11297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //   4. These MMI messages are caught in the PhoneApp
11307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //      (onMMIComplete) and the InCallScreen
11317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //      (mHandler.handleMessage) which bring up this dialog
11327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //      and closes the original progress dialog,
11337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //      respectively.
11347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //   5. If the message is anything other than PENDING,
11357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //      we are done, and the alert dialog (directly above)
11367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //      displays the outcome.
11377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //   6. If the network is requesting more information from
11387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //      the user, the MMI will be in a PENDING state, and
11397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //      we display this dialog with the message.
11407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //   7. User input, or cancel requests result in a return
11417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //      to step 1.  Keep in mind that this is the only
11427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //      time that a USSD should be canceled.
11437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
11447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // inflate the layout with the scrolling text area for the dialog.
11457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                LayoutInflater inflater = (LayoutInflater) context.getSystemService(
11467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        Context.LAYOUT_INFLATER_SERVICE);
11477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                View dialogView = inflater.inflate(R.layout.dialog_ussd_response, null);
11487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
11497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // get the input field.
11507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                final EditText inputText = (EditText) dialogView.findViewById(R.id.input_field);
11517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
11527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // specify the dialog's click listener, with SEND and CANCEL logic.
11537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                final DialogInterface.OnClickListener mUSSDDialogListener =
11547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    new DialogInterface.OnClickListener() {
11557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        public void onClick(DialogInterface dialog, int whichButton) {
11567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            switch (whichButton) {
11577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                case DialogInterface.BUTTON_POSITIVE:
11587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                    // As per spec 24.080, valid length of ussd string
11597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                    // is 1 - 160. If length is out of the range then
11607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                    // display toast message & Cancel MMI operation.
11617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                    if (inputText.length() < MIN_USSD_LEN
11627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                            || inputText.length() > MAX_USSD_LEN) {
11637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                        Toast.makeText(app,
11647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                                app.getResources().getString(R.string.enter_input,
11657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                                MIN_USSD_LEN, MAX_USSD_LEN),
11667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                                Toast.LENGTH_LONG).show();
11677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                        if (mmiCode.isCancelable()) {
11687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                            mmiCode.cancel();
11697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                        }
11707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                    } else {
11717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                        phone.sendUssdResponse(inputText.getText().toString());
11727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                    }
11737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                    break;
11747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                case DialogInterface.BUTTON_NEGATIVE:
11757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                    if (mmiCode.isCancelable()) {
11767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                        mmiCode.cancel();
11777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                    }
11787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                    break;
11797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            }
11807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        }
11817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    };
11827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
11837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // build the dialog
11847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                final AlertDialog newDialog = new AlertDialog.Builder(context)
11857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        .setMessage(text)
11867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        .setView(dialogView)
11877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        .setPositiveButton(R.string.send_button, mUSSDDialogListener)
11887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        .setNegativeButton(R.string.cancel, mUSSDDialogListener)
11897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        .setCancelable(false)
11907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        .create();
11917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
11927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // attach the key listener to the dialog's input field and make
11937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // sure focus is set.
11947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                final View.OnKeyListener mUSSDDialogInputListener =
11957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    new View.OnKeyListener() {
11967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        public boolean onKey(View v, int keyCode, KeyEvent event) {
11977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            switch (keyCode) {
11987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                case KeyEvent.KEYCODE_CALL:
11997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                case KeyEvent.KEYCODE_ENTER:
12007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                    if(event.getAction() == KeyEvent.ACTION_DOWN) {
12017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                        phone.sendUssdResponse(inputText.getText().toString());
12027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                        newDialog.dismiss();
12037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                    }
12047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                    return true;
12057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            }
12067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            return false;
12077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        }
12087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    };
12097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                inputText.setOnKeyListener(mUSSDDialogInputListener);
12107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                inputText.requestFocus();
12117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
12127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // set the window properties of the dialog
12137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                newDialog.getWindow().setType(
12147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
12157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                newDialog.getWindow().addFlags(
12167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        WindowManager.LayoutParams.FLAG_DIM_BEHIND);
12177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
12187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // now show the dialog!
12197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                newDialog.show();
12207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
12217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
12227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
12237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
12247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
12257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Cancels the current pending MMI operation, if applicable.
12267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return true if we canceled an MMI operation, or false
12277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *         if the current pending MMI wasn't cancelable
12287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *         or if there was no current pending MMI at all.
12297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
12307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @see displayMMIInitiate
12317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
12327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static boolean cancelMmiCode(Phone phone) {
12337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        List<? extends MmiCode> pendingMmis = phone.getPendingMmiCodes();
12347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        int count = pendingMmis.size();
12357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("cancelMmiCode: num pending MMIs = " + count);
12367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
12377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        boolean canceled = false;
12387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (count > 0) {
12397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // assume that we only have one pending MMI operation active at a time.
12407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // I don't think it's possible to enter multiple MMI codes concurrently
12417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // in the phone UI, because during the MMI operation, an Alert panel
12427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // is displayed, which prevents more MMI code from being entered.
12437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            MmiCode mmiCode = pendingMmis.get(0);
12447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (mmiCode.isCancelable()) {
12457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                mmiCode.cancel();
12467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                canceled = true;
12477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
12487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
12497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return canceled;
12507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
12517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
12527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public static class VoiceMailNumberMissingException extends Exception {
12537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        VoiceMailNumberMissingException() {
12547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            super();
12557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
12567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
12577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        VoiceMailNumberMissingException(String msg) {
12587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            super(msg);
12597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
12607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
12617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
12627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
12637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Given an Intent (which is presumably the ACTION_CALL intent that
12647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * initiated this outgoing call), figure out the actual phone number we
12657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * should dial.
12667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
12677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Note that the returned "number" may actually be a SIP address,
12687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * if the specified intent contains a sip: URI.
12697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
12707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * This method is basically a wrapper around PhoneUtils.getNumberFromIntent(),
12717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * except it's also aware of the EXTRA_ACTUAL_NUMBER_TO_DIAL extra.
12727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * (That extra, if present, tells us the exact string to pass down to the
12737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * telephony layer.  It's guaranteed to be safe to dial: it's either a PSTN
12747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * phone number with separators and keypad letters stripped out, or a raw
12757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * unencoded SIP address.)
12767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
12777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return the phone number corresponding to the specified Intent, or null
12787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *   if the Intent has no action or if the intent's data is malformed or
12797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *   missing.
12807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
12817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @throws VoiceMailNumberMissingException if the intent
12827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *   contains a "voicemail" URI, but there's no voicemail
12837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *   number configured on the device.
12847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
12857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public static String getInitialNumber(Intent intent)
12867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            throws PhoneUtils.VoiceMailNumberMissingException {
12877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("getInitialNumber(): " + intent);
12887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
12897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        String action = intent.getAction();
12907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (TextUtils.isEmpty(action)) {
12917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return null;
12927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
12937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
12947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // If the EXTRA_ACTUAL_NUMBER_TO_DIAL extra is present, get the phone
12957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // number from there.  (That extra takes precedence over the actual data
12967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // included in the intent.)
12977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (intent.hasExtra(OutgoingCallBroadcaster.EXTRA_ACTUAL_NUMBER_TO_DIAL)) {
12987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            String actualNumberToDial =
12997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    intent.getStringExtra(OutgoingCallBroadcaster.EXTRA_ACTUAL_NUMBER_TO_DIAL);
13007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG) {
13017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                log("==> got EXTRA_ACTUAL_NUMBER_TO_DIAL; returning '"
13027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        + toLogSafePhoneNumber(actualNumberToDial) + "'");
13037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
13047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return actualNumberToDial;
13057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
13067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
13077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return getNumberFromIntent(PhoneGlobals.getInstance(), intent);
13087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
13097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
13107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
13117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Gets the phone number to be called from an intent.  Requires a Context
13127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * to access the contacts database, and a Phone to access the voicemail
13137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * number.
13147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
13157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * <p>If <code>phone</code> is <code>null</code>, the function will return
13167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * <code>null</code> for <code>voicemail:</code> URIs;
13177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * if <code>context</code> is <code>null</code>, the function will return
13187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * <code>null</code> for person/phone URIs.</p>
13197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
13207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * <p>If the intent contains a <code>sip:</code> URI, the returned
13217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * "number" is actually the SIP address.
13227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
13237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param context a context to use (or
13247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param intent the intent
13257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
13267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @throws VoiceMailNumberMissingException if <code>intent</code> contains
13277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *         a <code>voicemail:</code> URI, but <code>phone</code> does not
13287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *         have a voicemail number set.
13297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
13307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return the phone number (or SIP address) that would be called by the intent,
13317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *         or <code>null</code> if the number cannot be found.
13327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
13337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static String getNumberFromIntent(Context context, Intent intent)
13347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            throws VoiceMailNumberMissingException {
13357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Uri uri = intent.getData();
13367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        String scheme = uri.getScheme();
13377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
13387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // The sip: scheme is simple: just treat the rest of the URI as a
13397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // SIP address.
13407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (Constants.SCHEME_SIP.equals(scheme)) {
13417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return uri.getSchemeSpecificPart();
13427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
13437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
13447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Otherwise, let PhoneNumberUtils.getNumberFromIntent() handle
13457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // the other cases (i.e. tel: and voicemail: and contact: URIs.)
13467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
13477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final String number = PhoneNumberUtils.getNumberFromIntent(intent, context);
13487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
13497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Check for a voicemail-dialing request.  If the voicemail number is
13507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // empty, throw a VoiceMailNumberMissingException.
13517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (Constants.SCHEME_VOICEMAIL.equals(scheme) &&
13527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                (number == null || TextUtils.isEmpty(number)))
13537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            throw new VoiceMailNumberMissingException();
13547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
13557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return number;
13567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
13577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
13587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
13597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Returns the caller-id info corresponding to the specified Connection.
13607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * (This is just a simple wrapper around CallerInfo.getCallerInfo(): we
13617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * extract a phone number from the specified Connection, and feed that
13627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * number into CallerInfo.getCallerInfo().)
13637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
13647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * The returned CallerInfo may be null in certain error cases, like if the
13657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * specified Connection was null, or if we weren't able to get a valid
13667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * phone number from the Connection.
13677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
13687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Finally, if the getCallerInfo() call did succeed, we save the resulting
13697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * CallerInfo object in the "userData" field of the Connection.
13707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
13717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * NOTE: This API should be avoided, with preference given to the
13727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * asynchronous startGetCallerInfo API.
13737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
13747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static CallerInfo getCallerInfo(Context context, Connection c) {
13757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        CallerInfo info = null;
13767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
13777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (c != null) {
13787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            //See if there is a URI attached.  If there is, this means
13797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            //that there is no CallerInfo queried yet, so we'll need to
13807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            //replace the URI with a full CallerInfo object.
13817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Object userDataObject = c.getUserData();
13827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (userDataObject instanceof Uri) {
13837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                info = CallerInfo.getCallerInfo(context, (Uri) userDataObject);
13847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (info != null) {
13857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    c.setUserData(info);
13867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
13877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            } else {
13887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (userDataObject instanceof CallerInfoToken) {
13897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    //temporary result, while query is running
13907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    info = ((CallerInfoToken) userDataObject).currentInfo;
13917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                } else {
13927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    //final query result
13937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    info = (CallerInfo) userDataObject;
13947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
13957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (info == null) {
13967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // No URI, or Existing CallerInfo, so we'll have to make do with
13977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // querying a new CallerInfo using the connection's phone number.
13987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    String number = c.getAddress();
13997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
14007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    if (DBG) log("getCallerInfo: number = " + toLogSafePhoneNumber(number));
14017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
14027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    if (!TextUtils.isEmpty(number)) {
14037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        info = CallerInfo.getCallerInfo(context, number);
14047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        if (info != null) {
14057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            c.setUserData(info);
14067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        }
14077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    }
14087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
14097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
14107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
14117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return info;
14127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
14137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
14147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
14157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Class returned by the startGetCallerInfo call to package a temporary
14167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * CallerInfo Object, to be superceded by the CallerInfo Object passed
14177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * into the listener when the query with token mAsyncQueryToken is complete.
14187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
14197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public static class CallerInfoToken {
14207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        /**indicates that there will no longer be updates to this request.*/
14217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        public boolean isFinal;
14227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
14237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        public CallerInfo currentInfo;
14247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        public CallerInfoAsyncQuery asyncQuery;
14257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
14267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
14277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
14287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Start a CallerInfo Query based on the earliest connection in the call.
14297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
14307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static CallerInfoToken startGetCallerInfo(Context context, Call call,
14317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            CallerInfoAsyncQuery.OnQueryCompleteListener listener, Object cookie) {
14327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Connection conn = null;
14337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        int phoneType = call.getPhone().getPhoneType();
14347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
14357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            conn = call.getLatestConnection();
14367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else if ((phoneType == PhoneConstants.PHONE_TYPE_GSM)
1437bd76e4e0407f75c4e6a6961cf943d36fc75a0e1aSailesh Nepal                || (phoneType == PhoneConstants.PHONE_TYPE_SIP)
1438bd76e4e0407f75c4e6a6961cf943d36fc75a0e1aSailesh Nepal                || (phoneType == PhoneConstants.PHONE_TYPE_THIRD_PARTY)) {
14397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            conn = call.getEarliestConnection();
14407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
14417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            throw new IllegalStateException("Unexpected phone type: " + phoneType);
14427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
14437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
14447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return startGetCallerInfo(context, conn, listener, cookie);
14457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
14467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1447e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng    static CallerInfoToken startGetCallerInfo(Context context, Connection c,
1448e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng            CallerInfoAsyncQuery.OnQueryCompleteListener listener, Object cookie) {
1449e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng        return startGetCallerInfo(context, c, listener, cookie, null);
1450e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng    }
1451e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng
14527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
14537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * place a temporary callerinfo object in the hands of the caller and notify
14547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * caller when the actual query is done.
14557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
14567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static CallerInfoToken startGetCallerInfo(Context context, Connection c,
1457e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng            CallerInfoAsyncQuery.OnQueryCompleteListener listener, Object cookie,
1458e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng            RawGatewayInfo info) {
14597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        CallerInfoToken cit;
14607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
14617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (c == null) {
14627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            //TODO: perhaps throw an exception here.
14637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            cit = new CallerInfoToken();
14647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            cit.asyncQuery = null;
14657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return cit;
14667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
14677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
14687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Object userDataObject = c.getUserData();
14697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
14707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // There are now 3 states for the Connection's userData object:
14717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //
14727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //   (1) Uri - query has not been executed yet
14737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //
14747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //   (2) CallerInfoToken - query is executing, but has not completed.
14757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //
14767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //   (3) CallerInfo - query has executed.
14777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //
14787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // In each case we have slightly different behaviour:
14797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //   1. If the query has not been executed yet (Uri or null), we start
14807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      query execution asynchronously, and note it by attaching a
14817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      CallerInfoToken as the userData.
14827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //   2. If the query is executing (CallerInfoToken), we've essentially
14837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      reached a state where we've received multiple requests for the
14847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      same callerInfo.  That means that once the query is complete,
14857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      we'll need to execute the additional listener requested.
14867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //   3. If the query has already been executed (CallerInfo), we just
14877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      return the CallerInfo object as expected.
14887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //   4. Regarding isFinal - there are cases where the CallerInfo object
14897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      will not be attached, like when the number is empty (caller id
14907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      blocking).  This flag is used to indicate that the
14917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      CallerInfoToken object is going to be permanent since no
14927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      query results will be returned.  In the case where a query
14937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      has been completed, this flag is used to indicate to the caller
14947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      that the data will not be updated since it is valid.
14957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //
14967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      Note: For the case where a number is NOT retrievable, we leave
14977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      the CallerInfo as null in the CallerInfoToken.  This is
14987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      something of a departure from the original code, since the old
14997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      code manufactured a CallerInfo object regardless of the query
15007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      outcome.  From now on, we will append an empty CallerInfo
15017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      object, to mirror previous behaviour, and to avoid Null Pointer
15027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      Exceptions.
15037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
15047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (userDataObject instanceof Uri) {
15057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // State (1): query has not been executed yet
15067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
15077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            //create a dummy callerinfo, populate with what we know from URI.
15087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            cit = new CallerInfoToken();
15097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            cit.currentInfo = new CallerInfo();
15107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            cit.asyncQuery = CallerInfoAsyncQuery.startQuery(QUERY_TOKEN, context,
15117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    (Uri) userDataObject, sCallerInfoQueryListener, c);
15127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            cit.asyncQuery.addQueryListener(QUERY_TOKEN, listener, cookie);
15137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            cit.isFinal = false;
15147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
15157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            c.setUserData(cit);
15167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
15177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG) log("startGetCallerInfo: query based on Uri: " + userDataObject);
15187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
15197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else if (userDataObject == null) {
15207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // No URI, or Existing CallerInfo, so we'll have to make do with
15217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // querying a new CallerInfo using the connection's phone number.
15227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            String number = c.getAddress();
15237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1524685dcb6b0268af57ac5b93a2e5b259eb519fa2d8Chiao Cheng            if (info != null && info != CallGatewayManager.EMPTY_INFO) {
1525e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng                // Gateway number, the connection number is actually the gateway number.
1526e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng                // need to lookup via dialed number.
1527e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng                number = info.trueNumber;
1528e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng            }
1529e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng
15307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG) {
15317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                log("PhoneUtils.startGetCallerInfo: new query for phone number...");
15327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                log("- number (address): " + toLogSafePhoneNumber(number));
15337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                log("- c: " + c);
15347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                log("- phone: " + c.getCall().getPhone());
15357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                int phoneType = c.getCall().getPhone().getPhoneType();
15367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                log("- phoneType: " + phoneType);
15377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                switch (phoneType) {
15387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    case PhoneConstants.PHONE_TYPE_NONE: log("  ==> PHONE_TYPE_NONE"); break;
15397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    case PhoneConstants.PHONE_TYPE_GSM: log("  ==> PHONE_TYPE_GSM"); break;
15407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    case PhoneConstants.PHONE_TYPE_CDMA: log("  ==> PHONE_TYPE_CDMA"); break;
15417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    case PhoneConstants.PHONE_TYPE_SIP: log("  ==> PHONE_TYPE_SIP"); break;
1542bd76e4e0407f75c4e6a6961cf943d36fc75a0e1aSailesh Nepal                    case PhoneConstants.PHONE_TYPE_THIRD_PARTY:
1543bd76e4e0407f75c4e6a6961cf943d36fc75a0e1aSailesh Nepal                        log("  ==> PHONE_TYPE_THIRD_PARTY");
1544bd76e4e0407f75c4e6a6961cf943d36fc75a0e1aSailesh Nepal                        break;
15457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    default: log("  ==> Unknown phone type"); break;
15467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
15477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
15487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
15497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            cit = new CallerInfoToken();
15507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            cit.currentInfo = new CallerInfo();
15517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
15527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // Store CNAP information retrieved from the Connection (we want to do this
15537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // here regardless of whether the number is empty or not).
15547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            cit.currentInfo.cnapName =  c.getCnapName();
15557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            cit.currentInfo.name = cit.currentInfo.cnapName; // This can still get overwritten
15567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                                             // by ContactInfo later
15577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            cit.currentInfo.numberPresentation = c.getNumberPresentation();
15587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            cit.currentInfo.namePresentation = c.getCnapNamePresentation();
15597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
15607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (VDBG) {
15617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                log("startGetCallerInfo: number = " + number);
15627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                log("startGetCallerInfo: CNAP Info from FW(1): name="
15637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    + cit.currentInfo.cnapName
15647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    + ", Name/Number Pres=" + cit.currentInfo.numberPresentation);
15657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
15667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
15677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // handling case where number is null (caller id hidden) as well.
15687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (!TextUtils.isEmpty(number)) {
15697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // Check for special CNAP cases and modify the CallerInfo accordingly
15707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // to be sure we keep the right information to display/log later
15717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                number = modifyForSpecialCnapCases(context, cit.currentInfo, number,
15727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        cit.currentInfo.numberPresentation);
15737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
15747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                cit.currentInfo.phoneNumber = number;
15757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // For scenarios where we may receive a valid number from the network but a
15767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // restricted/unavailable presentation, we do not want to perform a contact query
15777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // (see note on isFinal above). So we set isFinal to true here as well.
15787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (cit.currentInfo.numberPresentation != PhoneConstants.PRESENTATION_ALLOWED) {
15797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    cit.isFinal = true;
15807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                } else {
15817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    if (DBG) log("==> Actually starting CallerInfoAsyncQuery.startQuery()...");
15827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    cit.asyncQuery = CallerInfoAsyncQuery.startQuery(QUERY_TOKEN, context,
15837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            number, sCallerInfoQueryListener, c);
15847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    cit.asyncQuery.addQueryListener(QUERY_TOKEN, listener, cookie);
15857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    cit.isFinal = false;
15867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
15877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            } else {
15887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // This is the case where we are querying on a number that
15897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // is null or empty, like a caller whose caller id is
15907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // blocked or empty (CLIR).  The previous behaviour was to
15917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // throw a null CallerInfo object back to the user, but
15927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // this departure is somewhat cleaner.
15937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (DBG) log("startGetCallerInfo: No query to start, send trivial reply.");
15947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                cit.isFinal = true; // please see note on isFinal, above.
15957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
15967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
15977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            c.setUserData(cit);
15987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
15997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG) {
16007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                log("startGetCallerInfo: query based on number: " + toLogSafePhoneNumber(number));
16017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
16027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
16037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else if (userDataObject instanceof CallerInfoToken) {
16047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // State (2): query is executing, but has not completed.
16057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
16067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // just tack on this listener to the queue.
16077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            cit = (CallerInfoToken) userDataObject;
16087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
16097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // handling case where number is null (caller id hidden) as well.
16107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (cit.asyncQuery != null) {
16117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                cit.asyncQuery.addQueryListener(QUERY_TOKEN, listener, cookie);
16127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
16137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (DBG) log("startGetCallerInfo: query already running, adding listener: " +
16147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        listener.getClass().toString());
16157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            } else {
16167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // handling case where number/name gets updated later on by the network
16177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                String updatedNumber = c.getAddress();
1618e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng
1619e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng                if (info != null) {
1620e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng                    // Gateway number, the connection number is actually the gateway number.
1621e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng                    // need to lookup via dialed number.
1622e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng                    updatedNumber = info.trueNumber;
1623e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng                }
1624e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng
16257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (DBG) {
16267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    log("startGetCallerInfo: updatedNumber initially = "
16277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            + toLogSafePhoneNumber(updatedNumber));
16287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
16297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (!TextUtils.isEmpty(updatedNumber)) {
16307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // Store CNAP information retrieved from the Connection
16317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    cit.currentInfo.cnapName =  c.getCnapName();
16327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // This can still get overwritten by ContactInfo
16337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    cit.currentInfo.name = cit.currentInfo.cnapName;
16347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    cit.currentInfo.numberPresentation = c.getNumberPresentation();
16357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    cit.currentInfo.namePresentation = c.getCnapNamePresentation();
16367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
16377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    updatedNumber = modifyForSpecialCnapCases(context, cit.currentInfo,
16387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            updatedNumber, cit.currentInfo.numberPresentation);
16397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
16407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    cit.currentInfo.phoneNumber = updatedNumber;
16417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    if (DBG) {
16427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        log("startGetCallerInfo: updatedNumber="
16437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                + toLogSafePhoneNumber(updatedNumber));
16447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    }
16457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    if (VDBG) {
16467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        log("startGetCallerInfo: CNAP Info from FW(2): name="
16477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                + cit.currentInfo.cnapName
16487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                + ", Name/Number Pres=" + cit.currentInfo.numberPresentation);
16497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    } else if (DBG) {
16507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        log("startGetCallerInfo: CNAP Info from FW(2)");
16517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    }
16527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // For scenarios where we may receive a valid number from the network but a
16537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // restricted/unavailable presentation, we do not want to perform a contact query
16547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // (see note on isFinal above). So we set isFinal to true here as well.
16557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    if (cit.currentInfo.numberPresentation != PhoneConstants.PRESENTATION_ALLOWED) {
16567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        cit.isFinal = true;
16577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    } else {
16587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        cit.asyncQuery = CallerInfoAsyncQuery.startQuery(QUERY_TOKEN, context,
16597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                updatedNumber, sCallerInfoQueryListener, c);
16607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        cit.asyncQuery.addQueryListener(QUERY_TOKEN, listener, cookie);
16617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        cit.isFinal = false;
16627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    }
16637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                } else {
16647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    if (DBG) log("startGetCallerInfo: No query to attach to, send trivial reply.");
16657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    if (cit.currentInfo == null) {
16667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        cit.currentInfo = new CallerInfo();
16677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    }
16687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // Store CNAP information retrieved from the Connection
16697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    cit.currentInfo.cnapName = c.getCnapName();  // This can still get
16707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                                                 // overwritten by ContactInfo
16717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    cit.currentInfo.name = cit.currentInfo.cnapName;
16727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    cit.currentInfo.numberPresentation = c.getNumberPresentation();
16737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    cit.currentInfo.namePresentation = c.getCnapNamePresentation();
16747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
16757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    if (VDBG) {
16767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        log("startGetCallerInfo: CNAP Info from FW(3): name="
16777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                + cit.currentInfo.cnapName
16787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                + ", Name/Number Pres=" + cit.currentInfo.numberPresentation);
16797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    } else if (DBG) {
16807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        log("startGetCallerInfo: CNAP Info from FW(3)");
16817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    }
16827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    cit.isFinal = true; // please see note on isFinal, above.
16837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
16847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
16857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
16867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // State (3): query is complete.
16877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
16887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // The connection's userDataObject is a full-fledged
16897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // CallerInfo instance.  Wrap it in a CallerInfoToken and
16907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // return it to the user.
16917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
16927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            cit = new CallerInfoToken();
16937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            cit.currentInfo = (CallerInfo) userDataObject;
16947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            cit.asyncQuery = null;
16957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            cit.isFinal = true;
16967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // since the query is already done, call the listener.
16977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG) log("startGetCallerInfo: query already done, returning CallerInfo");
16987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG) log("==> cit.currentInfo = " + cit.currentInfo);
16997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
17007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return cit;
17017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
17027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
17037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
17047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Static CallerInfoAsyncQuery.OnQueryCompleteListener instance that
17057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * we use with all our CallerInfoAsyncQuery.startQuery() requests.
17067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
17077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static final int QUERY_TOKEN = -1;
17087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static CallerInfoAsyncQuery.OnQueryCompleteListener sCallerInfoQueryListener =
17097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        new CallerInfoAsyncQuery.OnQueryCompleteListener () {
17107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            /**
17117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon             * When the query completes, we stash the resulting CallerInfo
17127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon             * object away in the Connection's "userData" (where it will
17137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon             * later be retrieved by the in-call UI.)
17147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon             */
17157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            public void onQueryComplete(int token, Object cookie, CallerInfo ci) {
17167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (DBG) log("query complete, updating connection.userdata");
17177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Connection conn = (Connection) cookie;
17187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
17197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // Added a check if CallerInfo is coming from ContactInfo or from Connection.
17207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // If no ContactInfo, then we want to use CNAP information coming from network
17217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (DBG) log("- onQueryComplete: CallerInfo:" + ci);
17227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (ci.contactExists || ci.isEmergencyNumber() || ci.isVoiceMailNumber()) {
17237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // If the number presentation has not been set by
17247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // the ContactInfo, use the one from the
17257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // connection.
17267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
17277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // TODO: Need a new util method to merge the info
17287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // from the Connection in a CallerInfo object.
17297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // Here 'ci' is a new CallerInfo instance read
17307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // from the DB. It has lost all the connection
17317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // info preset before the query (see PhoneUtils
17327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // line 1334). We should have a method to merge
17337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // back into this new instance the info from the
17347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // connection object not set by the DB. If the
17357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // Connection already has a CallerInfo instance in
17367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // userData, then we could use this instance to
17377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // fill 'ci' in. The same routine could be used in
17387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // PhoneUtils.
17397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    if (0 == ci.numberPresentation) {
17407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        ci.numberPresentation = conn.getNumberPresentation();
17417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    }
17427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                } else {
17437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // No matching contact was found for this number.
17447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // Return a new CallerInfo based solely on the CNAP
17457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // information from the network.
17467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
17477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    CallerInfo newCi = getCallerInfo(null, conn);
17487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
17497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // ...but copy over the (few) things we care about
17507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // from the original CallerInfo object:
17517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    if (newCi != null) {
17527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        newCi.phoneNumber = ci.phoneNumber; // To get formatted phone number
17537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        newCi.geoDescription = ci.geoDescription; // To get geo description string
17547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        ci = newCi;
17557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    }
17567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
17577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
17587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (DBG) log("==> Stashing CallerInfo " + ci + " into the connection...");
17597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                conn.setUserData(ci);
17607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
17617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        };
17627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
17637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
17647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
17657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Returns a single "name" for the specified given a CallerInfo object.
17667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * If the name is null, return defaultString as the default value, usually
17677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * context.getString(R.string.unknown).
17687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
17697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static String getCompactNameFromCallerInfo(CallerInfo ci, Context context) {
17707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("getCompactNameFromCallerInfo: info = " + ci);
17717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
17727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        String compactName = null;
17737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (ci != null) {
17747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (TextUtils.isEmpty(ci.name)) {
17757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // Perform any modifications for special CNAP cases to
17767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // the phone number being displayed, if applicable.
17777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                compactName = modifyForSpecialCnapCases(context, ci, ci.phoneNumber,
17787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                                        ci.numberPresentation);
17797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            } else {
17807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // Don't call modifyForSpecialCnapCases on regular name. See b/2160795.
17817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                compactName = ci.name;
17827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
17837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
17847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
17857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if ((compactName == null) || (TextUtils.isEmpty(compactName))) {
17867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // If we're still null/empty here, then check if we have a presentation
17877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // string that takes precedence that we could return, otherwise display
17887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // "unknown" string.
17897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (ci != null && ci.numberPresentation == PhoneConstants.PRESENTATION_RESTRICTED) {
17907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                compactName = context.getString(R.string.private_num);
17917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            } else if (ci != null && ci.numberPresentation == PhoneConstants.PRESENTATION_PAYPHONE) {
17927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                compactName = context.getString(R.string.payphone);
17937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            } else {
17947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                compactName = context.getString(R.string.unknown);
17957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
17967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
17977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (VDBG) log("getCompactNameFromCallerInfo: compactName=" + compactName);
17987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return compactName;
17997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
18007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
18017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
18027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Returns true if the specified Call is a "conference call", meaning
18037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * that it owns more than one Connection object.  This information is
18047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * used to trigger certain UI changes that appear when a conference
18057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * call is active (like displaying the label "Conference call", and
18067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * enabling the "Manage conference" UI.)
18077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
18087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Watch out: This method simply checks the number of Connections,
18097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * *not* their states.  So if a Call has (for example) one ACTIVE
18107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * connection and one DISCONNECTED connection, this method will return
18117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * true (which is unintuitive, since the Call isn't *really* a
18127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * conference call any more.)
18137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
18147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return true if the specified call has more than one connection (in any state.)
18157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
18167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static boolean isConferenceCall(Call call) {
18177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // CDMA phones don't have the same concept of "conference call" as
18187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // GSM phones do; there's no special "conference call" state of
18197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // the UI or a "manage conference" function.  (Instead, when
18207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // you're in a 3-way call, all we can do is display the "generic"
18217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // state of the UI.)  So as far as the in-call UI is concerned,
18227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Conference corresponds to generic display.
18237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final PhoneGlobals app = PhoneGlobals.getInstance();
18247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        int phoneType = call.getPhone().getPhoneType();
18257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
18267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            CdmaPhoneCallState.PhoneCallState state = app.cdmaPhoneCallState.getCurrentCallState();
18277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if ((state == CdmaPhoneCallState.PhoneCallState.CONF_CALL)
18287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    || ((state == CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE)
18297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    && !app.cdmaPhoneCallState.IsThreeWayCallOrigStateDialing())) {
18307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                return true;
18317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
18327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
18337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            List<Connection> connections = call.getConnections();
18347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (connections != null && connections.size() > 1) {
18357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                return true;
18367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
18377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
18387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return false;
18397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
18407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // TODO: We may still want to change the semantics of this method
18417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // to say that a given call is only really a conference call if
18427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // the number of ACTIVE connections, not the total number of
18437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // connections, is greater than one.  (See warning comment in the
18447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // javadoc above.)
18457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Here's an implementation of that:
18467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //        if (connections == null) {
18477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //            return false;
18487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //        }
18497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //        int numActiveConnections = 0;
18507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //        for (Connection conn : connections) {
18517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //            if (DBG) log("  - CONN: " + conn + ", state = " + conn.getState());
18527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //            if (conn.getState() == Call.State.ACTIVE) numActiveConnections++;
18537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //            if (numActiveConnections > 1) {
18547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //                return true;
18557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //            }
18567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //        }
18577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //        return false;
18587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
18597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
18607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
18617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Launch the Dialer to start a new call.
18627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * This is just a wrapper around the ACTION_DIAL intent.
18637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
18647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /* package */ static boolean startNewCall(final CallManager cm) {
18657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final PhoneGlobals app = PhoneGlobals.getInstance();
18667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
18677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Sanity-check that this is OK given the current state of the phone.
18687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (!okToAddCall(cm)) {
18697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Log.w(LOG_TAG, "startNewCall: can't add a new call in the current state");
18707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            dumpCallManager();
18717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return false;
18727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
18737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
18747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Intent intent = new Intent(Intent.ACTION_DIAL);
18757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
18767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
18777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // when we request the dialer come up, we also want to inform
18787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // it that we're going through the "add call" option from the
18797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // InCallScreen / PhoneUtils.
18807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        intent.putExtra(ADD_CALL_MODE_KEY, true);
18817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        try {
18827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            app.startActivity(intent);
18837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } catch (ActivityNotFoundException e) {
18847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // This is rather rare but possible.
18857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // Note: this method is used even when the phone is encrypted. At that moment
18867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // the system may not find any Activity which can accept this Intent.
18877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Log.e(LOG_TAG, "Activity for adding calls isn't found.");
18887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return false;
18897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
18907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
18917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return true;
18927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
18937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
18947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
18957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Turns on/off speaker.
18967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
18977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param context Context
18987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param flag True when speaker should be on. False otherwise.
18997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param store True when the settings should be stored in the device.
19007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
19017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /* package */ static void turnOnSpeaker(Context context, boolean flag, boolean store) {
19027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("turnOnSpeaker(flag=" + flag + ", store=" + store + ")...");
19037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final PhoneGlobals app = PhoneGlobals.getInstance();
19047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
19057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
19067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        audioManager.setSpeakerphoneOn(flag);
19077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
19087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // record the speaker-enable value
19097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (store) {
19107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            sIsSpeakerEnabled = flag;
19117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
19127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
19137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Update the status bar icon
19147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        app.notificationMgr.updateSpeakerNotification(flag);
19157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
19167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // We also need to make a fresh call to PhoneApp.updateWakeState()
19177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // any time the speaker state changes, since the screen timeout is
19187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // sometimes different depending on whether or not the speaker is
19197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // in use.
19207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        app.updateWakeState();
19217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
19227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        app.mCM.setEchoSuppressionEnabled(flag);
19237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
19247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
19257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
19267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Restore the speaker mode, called after a wired headset disconnect
19277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * event.
19287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
19297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static void restoreSpeakerMode(Context context) {
19307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("restoreSpeakerMode, restoring to: " + sIsSpeakerEnabled);
19317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
19327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // change the mode if needed.
19337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (isSpeakerOn(context) != sIsSpeakerEnabled) {
19347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            turnOnSpeaker(context, sIsSpeakerEnabled, false);
19357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
19367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
19377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
19387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static boolean isSpeakerOn(Context context) {
19397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
19407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return audioManager.isSpeakerphoneOn();
19417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
19427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
19437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
19447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static void turnOnNoiseSuppression(Context context, boolean flag, boolean store) {
19457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("turnOnNoiseSuppression: " + flag);
19467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
19477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
19487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (!context.getResources().getBoolean(R.bool.has_in_call_noise_suppression)) {
19497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return;
19507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
19517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
19527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (flag) {
19537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            audioManager.setParameters("noise_suppression=auto");
19547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
19557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            audioManager.setParameters("noise_suppression=off");
19567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
19577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
19587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // record the speaker-enable value
19597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (store) {
19607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            sIsNoiseSuppressionEnabled = flag;
19617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
19627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
19637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // TODO: implement and manage ICON
19647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
19657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
19667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
19677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static void restoreNoiseSuppression(Context context) {
19687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("restoreNoiseSuppression, restoring to: " + sIsNoiseSuppressionEnabled);
19697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
19707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (!context.getResources().getBoolean(R.bool.has_in_call_noise_suppression)) {
19717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return;
19727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
19737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
19747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // change the mode if needed.
19757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (isNoiseSuppressionOn(context) != sIsNoiseSuppressionEnabled) {
19767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            turnOnNoiseSuppression(context, sIsNoiseSuppressionEnabled, false);
19777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
19787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
19797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
19807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static boolean isNoiseSuppressionOn(Context context) {
19817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
19827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (!context.getResources().getBoolean(R.bool.has_in_call_noise_suppression)) {
19837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return false;
19847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
19857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
19867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
19877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        String noiseSuppression = audioManager.getParameters("noise_suppression");
19887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("isNoiseSuppressionOn: " + noiseSuppression);
19897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (noiseSuppression.contains("off")) {
19907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return false;
19917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
19927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return true;
19937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
19947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
19957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
19967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
19977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
19987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Mute / umute the foreground phone, which has the current foreground call
19997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
20007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * All muting / unmuting from the in-call UI should go through this
20017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * wrapper.
20027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
20037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Wrapper around Phone.setMute() and setMicrophoneMute().
20047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * It also updates the connectionMuteTable and mute icon in the status bar.
20057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
20067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
20077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static void setMute(boolean muted) {
20087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        CallManager cm = PhoneGlobals.getInstance().mCM;
20097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2010c264cba0b6ea81b3f741d9c41a0a50b7ffd19220Santos Cordon        // Emergency calls never get muted.
2011c264cba0b6ea81b3f741d9c41a0a50b7ffd19220Santos Cordon        if (isInEmergencyCall(cm)) {
2012c264cba0b6ea81b3f741d9c41a0a50b7ffd19220Santos Cordon            muted = false;
2013c264cba0b6ea81b3f741d9c41a0a50b7ffd19220Santos Cordon        }
2014c264cba0b6ea81b3f741d9c41a0a50b7ffd19220Santos Cordon
20157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // make the call to mute the audio
20167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        setMuteInternal(cm.getFgPhone(), muted);
20177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
20187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // update the foreground connections to match.  This includes
20197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // all the connections on conference calls.
20207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        for (Connection cn : cm.getActiveFgCall().getConnections()) {
20217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (sConnectionMuteTable.get(cn) == null) {
20227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (DBG) log("problem retrieving mute value for this connection.");
20237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
20247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            sConnectionMuteTable.put(cn, Boolean.valueOf(muted));
20257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
2026bdc2da7f2e7a167d55e5fde7879133b56ef7b517Christine Chen
2027bdc2da7f2e7a167d55e5fde7879133b56ef7b517Christine Chen        // update the background connections to match.  This includes
2028bdc2da7f2e7a167d55e5fde7879133b56ef7b517Christine Chen        // all the connections on conference calls.
2029bdc2da7f2e7a167d55e5fde7879133b56ef7b517Christine Chen        if (cm.hasActiveBgCall()) {
2030bdc2da7f2e7a167d55e5fde7879133b56ef7b517Christine Chen            for (Connection cn : cm.getFirstActiveBgCall().getConnections()) {
2031bdc2da7f2e7a167d55e5fde7879133b56ef7b517Christine Chen                if (sConnectionMuteTable.get(cn) == null) {
2032bdc2da7f2e7a167d55e5fde7879133b56ef7b517Christine Chen                    if (DBG) log("problem retrieving mute value for this connection.");
2033bdc2da7f2e7a167d55e5fde7879133b56ef7b517Christine Chen                }
2034bdc2da7f2e7a167d55e5fde7879133b56ef7b517Christine Chen                sConnectionMuteTable.put(cn, Boolean.valueOf(muted));
2035bdc2da7f2e7a167d55e5fde7879133b56ef7b517Christine Chen            }
2036bdc2da7f2e7a167d55e5fde7879133b56ef7b517Christine Chen        }
20377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
20387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2039c264cba0b6ea81b3f741d9c41a0a50b7ffd19220Santos Cordon    static boolean isInEmergencyCall(CallManager cm) {
2040c264cba0b6ea81b3f741d9c41a0a50b7ffd19220Santos Cordon        for (Connection cn : cm.getActiveFgCall().getConnections()) {
2041c264cba0b6ea81b3f741d9c41a0a50b7ffd19220Santos Cordon            if (PhoneNumberUtils.isLocalEmergencyNumber(cn.getAddress(),
2042c264cba0b6ea81b3f741d9c41a0a50b7ffd19220Santos Cordon                    PhoneGlobals.getInstance())) {
2043c264cba0b6ea81b3f741d9c41a0a50b7ffd19220Santos Cordon                return true;
2044c264cba0b6ea81b3f741d9c41a0a50b7ffd19220Santos Cordon            }
2045c264cba0b6ea81b3f741d9c41a0a50b7ffd19220Santos Cordon        }
2046c264cba0b6ea81b3f741d9c41a0a50b7ffd19220Santos Cordon        return false;
2047c264cba0b6ea81b3f741d9c41a0a50b7ffd19220Santos Cordon    }
2048c264cba0b6ea81b3f741d9c41a0a50b7ffd19220Santos Cordon
20497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
20507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Internally used muting function.
20517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
20527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static void setMuteInternal(Phone phone, boolean muted) {
20537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final PhoneGlobals app = PhoneGlobals.getInstance();
20547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Context context = phone.getContext();
20557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        boolean routeToAudioManager =
20567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            context.getResources().getBoolean(R.bool.send_mic_mute_to_AudioManager);
20577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (routeToAudioManager) {
20587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            AudioManager audioManager =
20597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                (AudioManager) phone.getContext().getSystemService(Context.AUDIO_SERVICE);
20607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG) log("setMuteInternal: using setMicrophoneMute(" + muted + ")...");
20617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            audioManager.setMicrophoneMute(muted);
20627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
20637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG) log("setMuteInternal: using phone.setMute(" + muted + ")...");
20647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            phone.setMute(muted);
20657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
20667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        app.notificationMgr.updateMuteNotification();
2067cd95f62ea9f94c06d01debfcd1f01fd2cd6e2708Santos Cordon        app.getAudioRouter().onMuteChange(muted);
20687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
20697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
20707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
20717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Get the mute state of foreground phone, which has the current
20727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * foreground call
20737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
20747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static boolean getMute() {
20757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final PhoneGlobals app = PhoneGlobals.getInstance();
20767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
20777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        boolean routeToAudioManager =
20787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            app.getResources().getBoolean(R.bool.send_mic_mute_to_AudioManager);
20797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (routeToAudioManager) {
20807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            AudioManager audioManager =
20817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                (AudioManager) app.getSystemService(Context.AUDIO_SERVICE);
20827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return audioManager.isMicrophoneMute();
20837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
20847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return app.mCM.getMute();
20857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
20867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
20877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
20887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /* package */ static void setAudioMode() {
20897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        setAudioMode(PhoneGlobals.getInstance().mCM);
20907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
20917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
20927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
20937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Sets the audio mode per current phone state.
20947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
20957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /* package */ static void setAudioMode(CallManager cm) {
20967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) Log.d(LOG_TAG, "setAudioMode()..." + cm.getState());
20977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
20987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Context context = PhoneGlobals.getInstance();
20997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        AudioManager audioManager = (AudioManager)
21007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                context.getSystemService(Context.AUDIO_SERVICE);
21017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        int modeBefore = audioManager.getMode();
21027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        cm.setAudioMode();
21037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        int modeAfter = audioManager.getMode();
21047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
21057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (modeBefore != modeAfter) {
21067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // Enable stack dump only when actively debugging ("new Throwable()" is expensive!)
21077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG_SETAUDIOMODE_STACK) Log.d(LOG_TAG, "Stack:", new Throwable("stack dump"));
21087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
21097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG) Log.d(LOG_TAG, "setAudioMode() no change: "
21107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    + audioModeToString(modeBefore));
21117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
21127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
21137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static String audioModeToString(int mode) {
21147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        switch (mode) {
21157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            case AudioManager.MODE_INVALID: return "MODE_INVALID";
21167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            case AudioManager.MODE_CURRENT: return "MODE_CURRENT";
21177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            case AudioManager.MODE_NORMAL: return "MODE_NORMAL";
21187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            case AudioManager.MODE_RINGTONE: return "MODE_RINGTONE";
21197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            case AudioManager.MODE_IN_CALL: return "MODE_IN_CALL";
21207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            default: return String.valueOf(mode);
21217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
21227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
21237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
21247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
21257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Handles the wired headset button while in-call.
21267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
21277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * This is called from the PhoneApp, not from the InCallScreen,
21287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * since the HEADSETHOOK button means "mute or unmute the current
21297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * call" *any* time a call is active, even if the user isn't actually
21307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * on the in-call screen.
21317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
21327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return true if we consumed the event.
21337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
21347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /* package */ static boolean handleHeadsetHook(Phone phone, KeyEvent event) {
21357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("handleHeadsetHook()..." + event.getAction() + " " + event.getRepeatCount());
21367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final PhoneGlobals app = PhoneGlobals.getInstance();
21377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
21387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // If the phone is totally idle, we ignore HEADSETHOOK events
21397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // (and instead let them fall through to the media player.)
21407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (phone.getState() == PhoneConstants.State.IDLE) {
21417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return false;
21427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
21437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
21447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Ok, the phone is in use.
21457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // The headset button button means "Answer" if an incoming call is
21467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // ringing.  If not, it toggles the mute / unmute state.
21477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //
21487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // And in any case we *always* consume this event; this means
21497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // that the usual mediaplayer-related behavior of the headset
21507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // button will NEVER happen while the user is on a call.
21517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
21527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final boolean hasRingingCall = !phone.getRingingCall().isIdle();
21537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final boolean hasActiveCall = !phone.getForegroundCall().isIdle();
21547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final boolean hasHoldingCall = !phone.getBackgroundCall().isIdle();
21557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
21567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (hasRingingCall &&
21577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            event.getRepeatCount() == 0 &&
21587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            event.getAction() == KeyEvent.ACTION_UP) {
21597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // If an incoming call is ringing, answer it (just like with the
21607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // CALL button):
21617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            int phoneType = phone.getPhoneType();
21627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
21637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                answerCall(phone.getRingingCall());
21647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            } else if ((phoneType == PhoneConstants.PHONE_TYPE_GSM)
2165bd76e4e0407f75c4e6a6961cf943d36fc75a0e1aSailesh Nepal                    || (phoneType == PhoneConstants.PHONE_TYPE_SIP)
2166bd76e4e0407f75c4e6a6961cf943d36fc75a0e1aSailesh Nepal                    || (phoneType == PhoneConstants.PHONE_TYPE_THIRD_PARTY)) {
21677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (hasActiveCall && hasHoldingCall) {
21687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    if (DBG) log("handleHeadsetHook: ringing (both lines in use) ==> answer!");
21697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    answerAndEndActive(app.mCM, phone.getRingingCall());
21707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                } else {
21717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    if (DBG) log("handleHeadsetHook: ringing ==> answer!");
21727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // answerCall() will automatically hold the current
21737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // active call, if there is one.
21747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    answerCall(phone.getRingingCall());
21757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
21767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            } else {
21777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                throw new IllegalStateException("Unexpected phone type: " + phoneType);
21787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
21797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
21807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // No incoming ringing call.
21817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (event.isLongPress()) {
21827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (DBG) log("handleHeadsetHook: longpress -> hangup");
21837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                hangup(app.mCM);
21847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
21857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            else if (event.getAction() == KeyEvent.ACTION_UP &&
21867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                     event.getRepeatCount() == 0) {
21877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Connection c = phone.getForegroundCall().getLatestConnection();
21887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // If it is NOT an emg #, toggle the mute state. Otherwise, ignore the hook.
21897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (c != null && !PhoneNumberUtils.isLocalEmergencyNumber(c.getAddress(),
21907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                                                          PhoneGlobals.getInstance())) {
21917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    if (getMute()) {
21927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        if (DBG) log("handleHeadsetHook: UNmuting...");
21937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        setMute(false);
21947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    } else {
21957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        if (DBG) log("handleHeadsetHook: muting...");
21967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        setMute(true);
21977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    }
21987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
21997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
22007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
22017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
22027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Even if the InCallScreen is the current activity, there's no
22037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // need to force it to update, because (1) if we answered a
22047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // ringing call, the InCallScreen will imminently get a phone
22057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // state change event (causing an update), and (2) if we muted or
22067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // unmuted, the setMute() call automagically updates the status
22077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // bar, and there's no "mute" indication in the InCallScreen
22087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // itself (other than the menu item, which only ever stays
22097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // onscreen for a second anyway.)
22107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // TODO: (2) isn't entirely true anymore. Once we return our result
22117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // to the PhoneApp, we ask InCallScreen to update its control widgets
22127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // in case we changed mute or speaker state and phones with touch-
22137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // screen [toggle] buttons need to update themselves.
22147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
22157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return true;
22167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
22177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
22187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
22197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Look for ANY connections on the phone that qualify as being
22207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * disconnected.
22217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
22227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return true if we find a connection that is disconnected over
22237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * all the phone's call objects.
22247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
22257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /* package */ static boolean hasDisconnectedConnections(Phone phone) {
22267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return hasDisconnectedConnections(phone.getForegroundCall()) ||
22277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                hasDisconnectedConnections(phone.getBackgroundCall()) ||
22287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                hasDisconnectedConnections(phone.getRingingCall());
22297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
22307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
22317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
22327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Iterate over all connections in a call to see if there are any
22337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * that are not alive (disconnected or idle).
22347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
22357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return true if we find a connection that is disconnected, and
22367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * pending removal via
22377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * {@link com.android.internal.telephony.gsm.GsmCall#clearDisconnected()}.
22387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
22397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static final boolean hasDisconnectedConnections(Call call) {
22407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // look through all connections for non-active ones.
22417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        for (Connection c : call.getConnections()) {
22427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (!c.isAlive()) {
22437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                return true;
22447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
22457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
22467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return false;
22477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
22487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
22497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    //
22507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    // Misc UI policy helper functions
22517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    //
22527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
22537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
2254af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen     * @return true if we're allowed to hold calls, given the current
2255af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen     * state of the Phone.
2256af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen     */
2257af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen    /* package */ static boolean okToHoldCall(CallManager cm) {
2258af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen        final Call fgCall = cm.getActiveFgCall();
2259af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen        final boolean hasHoldingCall = cm.hasActiveBgCall();
2260af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen        final Call.State fgCallState = fgCall.getState();
2261af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen
2262af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen        // The "Hold" control is disabled entirely if there's
2263af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen        // no way to either hold or unhold in the current state.
2264af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen        final boolean okToHold = (fgCallState == Call.State.ACTIVE) && !hasHoldingCall;
2265af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen        final boolean okToUnhold = cm.hasActiveBgCall() && (fgCallState == Call.State.IDLE);
2266af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen        final boolean canHold = okToHold || okToUnhold;
2267af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen
2268af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen        return canHold;
2269af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen    }
2270af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen
2271af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen    /**
2272af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen     * @return true if we support holding calls, given the current
2273af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen     * state of the Phone.
2274af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen     */
2275af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen    /* package */ static boolean okToSupportHold(CallManager cm) {
2276af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen        boolean supportsHold = false;
2277af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen
2278af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen        final Call fgCall = cm.getActiveFgCall();
2279af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen        final boolean hasHoldingCall = cm.hasActiveBgCall();
2280af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen        final Call.State fgCallState = fgCall.getState();
2281af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen
2282af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen        if (TelephonyCapabilities.supportsHoldAndUnhold(fgCall.getPhone())) {
2283af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen            // This phone has the concept of explicit "Hold" and "Unhold" actions.
2284af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen            supportsHold = true;
2285af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen        } else if (hasHoldingCall && (fgCallState == Call.State.IDLE)) {
2286af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen            // Even when foreground phone device doesn't support hold/unhold, phone devices
2287af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen            // for background holding calls may do.
2288af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen            final Call bgCall = cm.getFirstActiveBgCall();
2289af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen            if (bgCall != null &&
2290af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen                    TelephonyCapabilities.supportsHoldAndUnhold(bgCall.getPhone())) {
2291af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen                supportsHold = true;
2292af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen            }
2293af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen        }
2294af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen        return supportsHold;
2295af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen    }
2296af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen
2297af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen    /**
22987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return true if we're allowed to swap calls, given the current
22997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * state of the Phone.
23007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
23017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /* package */ static boolean okToSwapCalls(CallManager cm) {
23027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        int phoneType = cm.getDefaultPhone().getPhoneType();
23037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
23047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // CDMA: "Swap" is enabled only when the phone reaches a *generic*.
23057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // state by either accepting a Call Waiting or by merging two calls
23067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            PhoneGlobals app = PhoneGlobals.getInstance();
23077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return (app.cdmaPhoneCallState.getCurrentCallState()
23087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    == CdmaPhoneCallState.PhoneCallState.CONF_CALL);
23097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else if ((phoneType == PhoneConstants.PHONE_TYPE_GSM)
2310bd76e4e0407f75c4e6a6961cf943d36fc75a0e1aSailesh Nepal                || (phoneType == PhoneConstants.PHONE_TYPE_SIP)
2311bd76e4e0407f75c4e6a6961cf943d36fc75a0e1aSailesh Nepal                || (phoneType == PhoneConstants.PHONE_TYPE_THIRD_PARTY)) {
23127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // GSM: "Swap" is available if both lines are in use and there's no
23137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // incoming call.  (Actually we need to verify that the active
23147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // call really is in the ACTIVE state and the holding call really
23157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // is in the HOLDING state, since you *can't* actually swap calls
23167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // when the foreground call is DIALING or ALERTING.)
23177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return !cm.hasActiveRingingCall()
23187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    && (cm.getActiveFgCall().getState() == Call.State.ACTIVE)
23197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    && (cm.getFirstActiveBgCall().getState() == Call.State.HOLDING);
23207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
23217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            throw new IllegalStateException("Unexpected phone type: " + phoneType);
23227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
23237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
23247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
23257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
23267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return true if we're allowed to merge calls, given the current
23277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * state of the Phone.
23287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
23297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /* package */ static boolean okToMergeCalls(CallManager cm) {
23307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        int phoneType = cm.getFgPhone().getPhoneType();
23317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
23327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // CDMA: "Merge" is enabled only when the user is in a 3Way call.
23337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            PhoneGlobals app = PhoneGlobals.getInstance();
23347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return ((app.cdmaPhoneCallState.getCurrentCallState()
23357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    == CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE)
23367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    && !app.cdmaPhoneCallState.IsThreeWayCallOrigStateDialing());
23377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
23387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // GSM: "Merge" is available if both lines are in use and there's no
23397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // incoming call, *and* the current conference isn't already
23407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // "full".
23417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // TODO: shall move all okToMerge logic to CallManager
23427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return !cm.hasActiveRingingCall() && cm.hasActiveFgCall()
23437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    && cm.hasActiveBgCall()
23447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    && cm.canConference(cm.getFirstActiveBgCall());
23457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
23467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
23477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
23487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
23497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return true if the UI should let you add a new call, given the current
23507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * state of the Phone.
23517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
23527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /* package */ static boolean okToAddCall(CallManager cm) {
23537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Phone phone = cm.getActiveFgCall().getPhone();
23547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
23557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // "Add call" is never allowed in emergency callback mode (ECM).
23567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (isPhoneInEcm(phone)) {
23577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return false;
23587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
23597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
23607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        int phoneType = phone.getPhoneType();
23617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final Call.State fgCallState = cm.getActiveFgCall().getState();
23627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
23637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon           // CDMA: "Add call" button is only enabled when:
23647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon           // - ForegroundCall is in ACTIVE state
23657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon           // - After 30 seconds of user Ignoring/Missing a Call Waiting call.
23667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            PhoneGlobals app = PhoneGlobals.getInstance();
23677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return ((fgCallState == Call.State.ACTIVE)
23687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    && (app.cdmaPhoneCallState.getAddCallMenuStateAfterCallWaiting()));
23697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else if ((phoneType == PhoneConstants.PHONE_TYPE_GSM)
2370bd76e4e0407f75c4e6a6961cf943d36fc75a0e1aSailesh Nepal                || (phoneType == PhoneConstants.PHONE_TYPE_SIP)
2371bd76e4e0407f75c4e6a6961cf943d36fc75a0e1aSailesh Nepal                || (phoneType == PhoneConstants.PHONE_TYPE_THIRD_PARTY)) {
23727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // GSM: "Add call" is available only if ALL of the following are true:
23737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // - There's no incoming ringing call
23747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // - There's < 2 lines in use
23757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // - The foreground call is ACTIVE or IDLE or DISCONNECTED.
23767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            //   (We mainly need to make sure it *isn't* DIALING or ALERTING.)
23777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            final boolean hasRingingCall = cm.hasActiveRingingCall();
23787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            final boolean hasActiveCall = cm.hasActiveFgCall();
23797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            final boolean hasHoldingCall = cm.hasActiveBgCall();
23807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            final boolean allLinesTaken = hasActiveCall && hasHoldingCall;
23817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
23827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return !hasRingingCall
23837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    && !allLinesTaken
23847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    && ((fgCallState == Call.State.ACTIVE)
23857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        || (fgCallState == Call.State.IDLE)
23867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        || (fgCallState == Call.State.DISCONNECTED));
23877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
23887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            throw new IllegalStateException("Unexpected phone type: " + phoneType);
23897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
23907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
23917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
23927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
23937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Based on the input CNAP number string,
23947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return _RESTRICTED or _UNKNOWN for all the special CNAP strings.
23957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Otherwise, return CNAP_SPECIAL_CASE_NO.
23967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
23977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static int checkCnapSpecialCases(String n) {
23987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (n.equals("PRIVATE") ||
23997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                n.equals("P") ||
24007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                n.equals("RES")) {
24017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG) log("checkCnapSpecialCases, PRIVATE string: " + n);
24027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return PhoneConstants.PRESENTATION_RESTRICTED;
24037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else if (n.equals("UNAVAILABLE") ||
24047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                n.equals("UNKNOWN") ||
24057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                n.equals("UNA") ||
24067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                n.equals("U")) {
24077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG) log("checkCnapSpecialCases, UNKNOWN string: " + n);
24087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return PhoneConstants.PRESENTATION_UNKNOWN;
24097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
24107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG) log("checkCnapSpecialCases, normal str. number: " + n);
24117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return CNAP_SPECIAL_CASE_NO;
24127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
24137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
24147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
24157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
24167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Handles certain "corner cases" for CNAP. When we receive weird phone numbers
24177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * from the network to indicate different number presentations, convert them to
24187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * expected number and presentation values within the CallerInfo object.
24197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param number number we use to verify if we are in a corner case
24207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param presentation presentation value used to verify if we are in a corner case
24217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return the new String that should be used for the phone number
24227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
24237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /* package */ static String modifyForSpecialCnapCases(Context context, CallerInfo ci,
24247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            String number, int presentation) {
24257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Obviously we return number if ci == null, but still return number if
24267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // number == null, because in these cases the correct string will still be
24277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // displayed/logged after this function returns based on the presentation value.
24287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (ci == null || number == null) return number;
24297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
24307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) {
24317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            log("modifyForSpecialCnapCases: initially, number="
24327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    + toLogSafePhoneNumber(number)
24337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    + ", presentation=" + presentation + " ci " + ci);
24347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
24357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
24367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // "ABSENT NUMBER" is a possible value we could get from the network as the
24377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // phone number, so if this happens, change it to "Unknown" in the CallerInfo
24387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // and fix the presentation to be the same.
24397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final String[] absentNumberValues =
24407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                context.getResources().getStringArray(R.array.absent_num);
24417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (Arrays.asList(absentNumberValues).contains(number)
24427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                && presentation == PhoneConstants.PRESENTATION_ALLOWED) {
24437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            number = context.getString(R.string.unknown);
24447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            ci.numberPresentation = PhoneConstants.PRESENTATION_UNKNOWN;
24457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
24467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
24477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Check for other special "corner cases" for CNAP and fix them similarly. Corner
24487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // cases only apply if we received an allowed presentation from the network, so check
24497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // if we think we have an allowed presentation, or if the CallerInfo presentation doesn't
24507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // match the presentation passed in for verification (meaning we changed it previously
24517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // because it's a corner case and we're being called from a different entry point).
24527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (ci.numberPresentation == PhoneConstants.PRESENTATION_ALLOWED
24537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                || (ci.numberPresentation != presentation
24547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        && presentation == PhoneConstants.PRESENTATION_ALLOWED)) {
24557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            int cnapSpecialCase = checkCnapSpecialCases(number);
24567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (cnapSpecialCase != CNAP_SPECIAL_CASE_NO) {
24577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // For all special strings, change number & numberPresentation.
24587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (cnapSpecialCase == PhoneConstants.PRESENTATION_RESTRICTED) {
24597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    number = context.getString(R.string.private_num);
24607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                } else if (cnapSpecialCase == PhoneConstants.PRESENTATION_UNKNOWN) {
24617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    number = context.getString(R.string.unknown);
24627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
24637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (DBG) {
24647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    log("SpecialCnap: number=" + toLogSafePhoneNumber(number)
24657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            + "; presentation now=" + cnapSpecialCase);
24667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
24677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                ci.numberPresentation = cnapSpecialCase;
24687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
24697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
24707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) {
24717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            log("modifyForSpecialCnapCases: returning number string="
24727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    + toLogSafePhoneNumber(number));
24737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
24747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return number;
24757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
24767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
24777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    //
24787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    // Support for 3rd party phone service providers.
24797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    //
24807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
24817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
24827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Check if a phone number can be route through a 3rd party
24837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * gateway. The number must be a global phone number in numerical
24847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * form (1-800-666-SEXY won't work).
24857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
24867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * MMI codes and the like cannot be used as a dial number for the
24877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * gateway either.
24887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
24897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param number To be dialed via a 3rd party gateway.
24907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return true If the number can be routed through the 3rd party network.
24917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
249269a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon    private static boolean isRoutableViaGateway(String number) {
24937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (TextUtils.isEmpty(number)) {
24947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return false;
24957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
24967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        number = PhoneNumberUtils.stripSeparators(number);
24977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (!number.equals(PhoneNumberUtils.convertKeypadLettersToDigits(number))) {
24987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return false;
24997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
25007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        number = PhoneNumberUtils.extractNetworkPortion(number);
25017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return PhoneNumberUtils.isGlobalPhoneNumber(number);
25027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
25037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
25047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon   /**
25057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    * This function is called when phone answers or places a call.
25067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    * Check if the phone is in a car dock or desk dock.
25077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    * If yes, turn on the speaker, when no wired or BT headsets are connected.
25087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    * Otherwise do nothing.
25097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    * @return true if activated
25107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    */
25117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static boolean activateSpeakerIfDocked(Phone phone) {
25127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("activateSpeakerIfDocked()...");
25137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
25147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        boolean activated = false;
25157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (PhoneGlobals.mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED) {
25167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG) log("activateSpeakerIfDocked(): In a dock -> may need to turn on speaker.");
2517593ab38970a84a60ac39edba4306647c8b66436dSantos Cordon            final PhoneGlobals app = PhoneGlobals.getInstance();
2518593ab38970a84a60ac39edba4306647c8b66436dSantos Cordon
25193e0f0414daa2266dc51b77198fe433797f7d610aChristine Chen            // TODO: This function should move to AudioRouter
252027a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon            final BluetoothManager btManager = app.getBluetoothManager();
2521593ab38970a84a60ac39edba4306647c8b66436dSantos Cordon            final WiredHeadsetManager wiredHeadset = app.getWiredHeadsetManager();
2522593ab38970a84a60ac39edba4306647c8b66436dSantos Cordon            final AudioRouter audioRouter = app.getAudioRouter();
25237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2524593ab38970a84a60ac39edba4306647c8b66436dSantos Cordon            if (!wiredHeadset.isHeadsetPlugged() && !btManager.isBluetoothHeadsetAudioOn()) {
2525593ab38970a84a60ac39edba4306647c8b66436dSantos Cordon                audioRouter.setSpeaker(true);
25267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                activated = true;
25277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
25287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
25297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return activated;
25307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
25317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
25327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
25337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
25347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Returns whether the phone is in ECM ("Emergency Callback Mode") or not.
25357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
25367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /* package */ static boolean isPhoneInEcm(Phone phone) {
25377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if ((phone != null) && TelephonyCapabilities.supportsEcm(phone)) {
25387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // For phones that support ECM, return true iff PROPERTY_INECM_MODE == "true".
25397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // TODO: There ought to be a better API for this than just
25407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // exposing a system property all the way up to the app layer,
25417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // probably a method like "inEcm()" provided by the telephony
25427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // layer.
25437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            String ecmMode =
25447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE);
25457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (ecmMode != null) {
25467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                return ecmMode.equals("true");
25477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
25487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
25497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return false;
25507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
25517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
25527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
25537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Returns the most appropriate Phone object to handle a call
25547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * to the specified number.
25557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
25567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param cm the CallManager.
25577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param scheme the scheme from the data URI that the number originally came from.
25587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param number the phone number, or SIP address.
25597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
2560bfb6832c4bcc535aef12b07ac5bcf4a973c65d00Sailesh Nepal    public static Phone pickPhoneBasedOnNumber(CallManager cm, String scheme, String number,
2561bfb6832c4bcc535aef12b07ac5bcf4a973c65d00Sailesh Nepal            String primarySipUri, ComponentName thirdPartyCallComponent) {
25627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) {
25637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            log("pickPhoneBasedOnNumber: scheme " + scheme
25647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    + ", number " + toLogSafePhoneNumber(number)
25657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    + ", sipUri "
2566bfb6832c4bcc535aef12b07ac5bcf4a973c65d00Sailesh Nepal                    + (primarySipUri != null ? Uri.parse(primarySipUri).toSafeString() : "null")
2567bfb6832c4bcc535aef12b07ac5bcf4a973c65d00Sailesh Nepal                    + ", thirdPartyCallComponent: " + thirdPartyCallComponent);
25687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
25697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
25707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (primarySipUri != null) {
25717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Phone phone = getSipPhoneFromUri(cm, primarySipUri);
25727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (phone != null) return phone;
25737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
2574bfb6832c4bcc535aef12b07ac5bcf4a973c65d00Sailesh Nepal
2575bfb6832c4bcc535aef12b07ac5bcf4a973c65d00Sailesh Nepal        if (thirdPartyCallComponent != null) {
2576bfb6832c4bcc535aef12b07ac5bcf4a973c65d00Sailesh Nepal            return getThirdPartyPhoneFromComponent(cm, thirdPartyCallComponent);
2577bfb6832c4bcc535aef12b07ac5bcf4a973c65d00Sailesh Nepal        }
2578bfb6832c4bcc535aef12b07ac5bcf4a973c65d00Sailesh Nepal
25797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return cm.getDefaultPhone();
25807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
25817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
25827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public static Phone getSipPhoneFromUri(CallManager cm, String target) {
25837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        for (Phone phone : cm.getAllPhones()) {
25847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_SIP) {
25857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                String sipUri = ((SipPhone) phone).getSipUri();
25867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (target.equals(sipUri)) {
25877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    if (DBG) log("- pickPhoneBasedOnNumber:" +
25887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            "found SipPhone! obj = " + phone + ", "
25897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            + phone.getClass());
25907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    return phone;
25917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
25927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
25937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
25947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return null;
25957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
25967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2597bfb6832c4bcc535aef12b07ac5bcf4a973c65d00Sailesh Nepal    public static Phone getThirdPartyPhoneFromComponent(CallManager cm, ComponentName component) {
2598bfb6832c4bcc535aef12b07ac5bcf4a973c65d00Sailesh Nepal        for (Phone phone : cm.getAllPhones()) {
2599bfb6832c4bcc535aef12b07ac5bcf4a973c65d00Sailesh Nepal            if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_THIRD_PARTY) {
2600bfb6832c4bcc535aef12b07ac5bcf4a973c65d00Sailesh Nepal                ThirdPartyPhone thirdPartyPhone = (ThirdPartyPhone) phone;
2601bfb6832c4bcc535aef12b07ac5bcf4a973c65d00Sailesh Nepal                if (thirdPartyPhone.getCallProviderComponent().equals(component)) {
2602bfb6832c4bcc535aef12b07ac5bcf4a973c65d00Sailesh Nepal                    return thirdPartyPhone;
2603bfb6832c4bcc535aef12b07ac5bcf4a973c65d00Sailesh Nepal                }
2604bfb6832c4bcc535aef12b07ac5bcf4a973c65d00Sailesh Nepal            }
2605bfb6832c4bcc535aef12b07ac5bcf4a973c65d00Sailesh Nepal        }
2606bfb6832c4bcc535aef12b07ac5bcf4a973c65d00Sailesh Nepal        ThirdPartyPhone thirdPartyPhone = PhoneFactory.makeThirdPartyPhone(component);
2607bfb6832c4bcc535aef12b07ac5bcf4a973c65d00Sailesh Nepal        cm.registerPhone(thirdPartyPhone);
2608bfb6832c4bcc535aef12b07ac5bcf4a973c65d00Sailesh Nepal        return thirdPartyPhone;
2609bfb6832c4bcc535aef12b07ac5bcf4a973c65d00Sailesh Nepal    }
2610bfb6832c4bcc535aef12b07ac5bcf4a973c65d00Sailesh Nepal
26117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
26127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Returns true when the given call is in INCOMING state and there's no foreground phone call,
26137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * meaning the call is the first real incoming call the phone is having.
26147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
26157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public static boolean isRealIncomingCall(Call.State state) {
26167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return (state == Call.State.INCOMING && !PhoneGlobals.getInstance().mCM.hasActiveFgCall());
26177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
26187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
26197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static boolean sVoipSupported = false;
26207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static {
26217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        PhoneGlobals app = PhoneGlobals.getInstance();
26227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        sVoipSupported = SipManager.isVoipSupported(app)
26237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                && app.getResources().getBoolean(com.android.internal.R.bool.config_built_in_sip_phone)
26247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                && app.getResources().getBoolean(com.android.internal.R.bool.config_voice_capable);
26257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
26267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
26277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
26287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return true if this device supports voice calls using the built-in SIP stack.
26297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
26307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static boolean isVoipSupported() {
26317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return sVoipSupported;
26327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
26337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
26347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public static String getPresentationString(Context context, int presentation) {
26357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        String name = context.getString(R.string.unknown);
26367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (presentation == PhoneConstants.PRESENTATION_RESTRICTED) {
26377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            name = context.getString(R.string.private_num);
26387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else if (presentation == PhoneConstants.PRESENTATION_PAYPHONE) {
26397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            name = context.getString(R.string.payphone);
26407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
26417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return name;
26427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
26437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
26447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public static void sendViewNotificationAsync(Context context, Uri contactUri) {
26457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) Log.d(LOG_TAG, "Send view notification to Contacts (uri: " + contactUri + ")");
26467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Intent intent = new Intent("com.android.contacts.VIEW_NOTIFICATION", contactUri);
26477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        intent.setClassName("com.android.contacts",
26487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                "com.android.contacts.ViewNotificationService");
26497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        context.startService(intent);
26507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
26517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
26527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    //
26537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    // General phone and call state debugging/testing code
26547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    //
26557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
26567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /* package */ static void dumpCallState(Phone phone) {
26577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        PhoneGlobals app = PhoneGlobals.getInstance();
26587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Log.d(LOG_TAG, "dumpCallState():");
26597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Log.d(LOG_TAG, "- Phone: " + phone + ", name = " + phone.getPhoneName()
26607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon              + ", state = " + phone.getState());
26617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
26627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        StringBuilder b = new StringBuilder(128);
26637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
26647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Call call = phone.getForegroundCall();
26657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.setLength(0);
26667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append("  - FG call: ").append(call.getState());
26677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" isAlive ").append(call.getState().isAlive());
26687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" isRinging ").append(call.getState().isRinging());
26697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" isDialing ").append(call.getState().isDialing());
26707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" isIdle ").append(call.isIdle());
26717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" hasConnections ").append(call.hasConnections());
26727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Log.d(LOG_TAG, b.toString());
26737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
26747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        call = phone.getBackgroundCall();
26757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.setLength(0);
26767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append("  - BG call: ").append(call.getState());
26777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" isAlive ").append(call.getState().isAlive());
26787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" isRinging ").append(call.getState().isRinging());
26797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" isDialing ").append(call.getState().isDialing());
26807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" isIdle ").append(call.isIdle());
26817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" hasConnections ").append(call.hasConnections());
26827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Log.d(LOG_TAG, b.toString());
26837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
26847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        call = phone.getRingingCall();
26857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.setLength(0);
26867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append("  - RINGING call: ").append(call.getState());
26877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" isAlive ").append(call.getState().isAlive());
26887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" isRinging ").append(call.getState().isRinging());
26897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" isDialing ").append(call.getState().isDialing());
26907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" isIdle ").append(call.isIdle());
26917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" hasConnections ").append(call.hasConnections());
26927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Log.d(LOG_TAG, b.toString());
26937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
26947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
26957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final boolean hasRingingCall = !phone.getRingingCall().isIdle();
26967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final boolean hasActiveCall = !phone.getForegroundCall().isIdle();
26977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final boolean hasHoldingCall = !phone.getBackgroundCall().isIdle();
26987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final boolean allLinesTaken = hasActiveCall && hasHoldingCall;
26997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.setLength(0);
27007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append("  - hasRingingCall ").append(hasRingingCall);
27017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" hasActiveCall ").append(hasActiveCall);
27027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" hasHoldingCall ").append(hasHoldingCall);
27037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" allLinesTaken ").append(allLinesTaken);
27047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Log.d(LOG_TAG, b.toString());
27057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
27067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // On CDMA phones, dump out the CdmaPhoneCallState too:
27077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {
27087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (app.cdmaPhoneCallState != null) {
27097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Log.d(LOG_TAG, "  - CDMA call state: "
27107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                      + app.cdmaPhoneCallState.getCurrentCallState());
27117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            } else {
27127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Log.d(LOG_TAG, "  - CDMA device, but null cdmaPhoneCallState!");
27137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
27147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
27157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
27167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Watch out: the isRinging() call below does NOT tell us anything
27177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // about the state of the telephony layer; it merely tells us whether
27187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // the Ringer manager is currently playing the ringtone.
27197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        boolean ringing = app.getRinger().isRinging();
27207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Log.d(LOG_TAG, "  - Ringer state: " + ringing);
27217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
27227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
27237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static void log(String msg) {
27247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Log.d(LOG_TAG, msg);
27257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
27267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
27277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static void dumpCallManager() {
27287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Call call;
27297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        CallManager cm = PhoneGlobals.getInstance().mCM;
27307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        StringBuilder b = new StringBuilder(128);
27317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
27327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
27337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
27347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Log.d(LOG_TAG, "############### dumpCallManager() ##############");
27357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // TODO: Don't log "cm" itself, since CallManager.toString()
27367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // already spews out almost all this same information.
27377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // We should fix CallManager.toString() to be more minimal, and
27387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // use an explicit dumpState() method for the verbose dump.
27397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Log.d(LOG_TAG, "CallManager: " + cm
27407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //         + ", state = " + cm.getState());
27417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Log.d(LOG_TAG, "CallManager: state = " + cm.getState());
27427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.setLength(0);
27437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        call = cm.getActiveFgCall();
27447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" - FG call: ").append(cm.hasActiveFgCall()? "YES ": "NO ");
27457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(call);
27467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append( "  State: ").append(cm.getActiveFgCallState());
27477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append( "  Conn: ").append(cm.getFgCallConnections());
27487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Log.d(LOG_TAG, b.toString());
27497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.setLength(0);
27507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        call = cm.getFirstActiveBgCall();
27517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" - BG call: ").append(cm.hasActiveBgCall()? "YES ": "NO ");
27527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(call);
27537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append( "  State: ").append(cm.getFirstActiveBgCall().getState());
27547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append( "  Conn: ").append(cm.getBgCallConnections());
27557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Log.d(LOG_TAG, b.toString());
27567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.setLength(0);
27577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        call = cm.getFirstActiveRingingCall();
27587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" - RINGING call: ").append(cm.hasActiveRingingCall()? "YES ": "NO ");
27597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(call);
27607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append( "  State: ").append(cm.getFirstActiveRingingCall().getState());
27617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Log.d(LOG_TAG, b.toString());
27627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
27637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
27647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
27657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        for (Phone phone : CallManager.getInstance().getAllPhones()) {
27667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (phone != null) {
27677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Log.d(LOG_TAG, "Phone: " + phone + ", name = " + phone.getPhoneName()
27687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        + ", state = " + phone.getState());
27697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                b.setLength(0);
27707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                call = phone.getForegroundCall();
27717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                b.append(" - FG call: ").append(call);
27727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                b.append( "  State: ").append(call.getState());
27737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                b.append( "  Conn: ").append(call.hasConnections());
27747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Log.d(LOG_TAG, b.toString());
27757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                b.setLength(0);
27767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                call = phone.getBackgroundCall();
27777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                b.append(" - BG call: ").append(call);
27787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                b.append( "  State: ").append(call.getState());
27797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                b.append( "  Conn: ").append(call.hasConnections());
27807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Log.d(LOG_TAG, b.toString());b.setLength(0);
27817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                call = phone.getRingingCall();
27827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                b.append(" - RINGING call: ").append(call);
27837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                b.append( "  State: ").append(call.getState());
27847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                b.append( "  Conn: ").append(call.hasConnections());
27857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Log.d(LOG_TAG, b.toString());
27867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
27877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
27887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
27897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Log.d(LOG_TAG, "############## END dumpCallManager() ###############");
27907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
27917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
27927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
27937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return if the context is in landscape orientation.
27947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
27957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public static boolean isLandscape(Context context) {
27967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return context.getResources().getConfiguration().orientation
27977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                == Configuration.ORIENTATION_LANDSCAPE;
27987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
27997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon}
2800