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