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.res.Configuration;
297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.media.AudioManager;
307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.net.Uri;
317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.os.Handler;
327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.os.Message;
333b9c21fad915066c537fde5a8bf83fdc65891085Jonathan Basseriimport android.os.PersistableBundle;
347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.os.RemoteException;
357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.os.SystemProperties;
364d45d1cf58a2003378fd35912d6d73a00001bf06Tyler Gunnimport android.telecom.PhoneAccount;
37d5165b05c851ecd47d330b600ed2768e0db8b9d1Andrew Leeimport android.telecom.PhoneAccountHandle;
384d45d1cf58a2003378fd35912d6d73a00001bf06Tyler Gunnimport android.telecom.VideoProfile;
393b9c21fad915066c537fde5a8bf83fdc65891085Jonathan Basseriimport android.telephony.CarrierConfigManager;
407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.telephony.PhoneNumberUtils;
41f69df96f713523a8b078aa6ef922e3e752a1a594Santos Cordonimport android.telephony.SubscriptionManager;
427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.text.TextUtils;
437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.util.Log;
44b3ee4dc3dd39ebe765ebe6b535b3900bb95813d8Andrew Leeimport android.view.ContextThemeWrapper;
457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.view.KeyEvent;
467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.view.LayoutInflater;
477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.view.View;
487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.view.WindowManager;
497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.widget.EditText;
507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.widget.Toast;
517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport com.android.internal.telephony.Call;
537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport com.android.internal.telephony.CallManager;
547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport com.android.internal.telephony.CallStateException;
557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport com.android.internal.telephony.CallerInfo;
567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport com.android.internal.telephony.CallerInfoAsyncQuery;
577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport com.android.internal.telephony.Connection;
58dcf40a9cc562d95f826123d8d670262c8d15e7bdStuart Scottimport com.android.internal.telephony.IccCard;
597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport com.android.internal.telephony.MmiCode;
607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport com.android.internal.telephony.Phone;
617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport com.android.internal.telephony.PhoneConstants;
62dcf40a9cc562d95f826123d8d670262c8d15e7bdStuart Scottimport com.android.internal.telephony.PhoneFactory;
637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport com.android.internal.telephony.TelephonyCapabilities;
647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport com.android.internal.telephony.TelephonyProperties;
657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport com.android.internal.telephony.sip.SipPhone;
6669a691914e9b013a7ff52c129d8466c152ed7239Santos Cordonimport com.android.phone.CallGatewayManager.RawGatewayInfo;
677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport java.util.Arrays;
697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport java.util.List;
707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon/**
727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon * Misc utilities for the Phone app.
737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon */
747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonpublic class PhoneUtils {
75d3edc2292d969ecf8df96281c50e1a8f7a3fc777Brad Ebinger    public static final String EMERGENCY_ACCOUNT_HANDLE_ID = "E";
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()
89f78851443a876b706e36e3e9925049557486bdc1fionaxu    public static final int CALL_STATUS_DIALED = 0;  // The number was successfully dialed
90f78851443a876b706e36e3e9925049557486bdc1fionaxu    public static final int CALL_STATUS_DIALED_MMI = 1;  // The specified number was an MMI code
91f78851443a876b706e36e3e9925049557486bdc1fionaxu    public 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    /** Static handler for the connection/mute tracking */
1087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static ConnectionHandler mConnectionHandler;
1097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /** Phone state changed event*/
1117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static final int PHONE_STATE_CHANGED = -1;
1127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
113a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu    /** check status then decide whether answerCall */
114a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu    private static final int MSG_CHECK_STATUS_ANSWERCALL = 100;
115a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu
116a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu    /** poll phone DISCONNECTING status interval */
117a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu    private static final int DISCONNECTING_POLLING_INTERVAL_MS = 200;
118a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu
119a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu    /** poll phone DISCONNECTING status times limit */
120a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu    private static final int DISCONNECTING_POLLING_TIMES_LIMIT = 8;
121a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu
1227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /** Define for not a special CNAP string */
1237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static final int CNAP_SPECIAL_CASE_NO = -1;
1247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /** Noise suppression status as selected by user */
1267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static boolean sIsNoiseSuppressionEnabled = true;
1277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
128e0f2b791135a88de7930e4339686fd5b79e53a9fYorke Lee    /**
129e0f2b791135a88de7930e4339686fd5b79e53a9fYorke Lee     * Theme to use for dialogs displayed by utility methods in this class. This is needed
130e0f2b791135a88de7930e4339686fd5b79e53a9fYorke Lee     * because these dialogs are displayed using the application context, which does not resolve
131e0f2b791135a88de7930e4339686fd5b79e53a9fYorke Lee     * the dialog theme correctly.
132e0f2b791135a88de7930e4339686fd5b79e53a9fYorke Lee     */
133e0f2b791135a88de7930e4339686fd5b79e53a9fYorke Lee    private static final int THEME = AlertDialog.THEME_DEVICE_DEFAULT_LIGHT;
134e0f2b791135a88de7930e4339686fd5b79e53a9fYorke Lee
135a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu    private static class FgRingCalls {
136a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu        private Call fgCall;
137a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu        private Call ringing;
138a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu        public FgRingCalls(Call fg, Call ring) {
139a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu            fgCall = fg;
140a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu            ringing = ring;
141a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu        }
142a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu    }
143a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu
14437abbab24baec145cdf995693be96cd7162b0c06Etan Cohen    /** USSD information used to aggregate all USSD messages */
14537abbab24baec145cdf995693be96cd7162b0c06Etan Cohen    private static AlertDialog sUssdDialog = null;
14637abbab24baec145cdf995693be96cd7162b0c06Etan Cohen    private static StringBuilder sUssdMsg = new StringBuilder();
14737abbab24baec145cdf995693be96cd7162b0c06Etan Cohen
1484c8f3c63b75ba080ab697b2e8e0f1e3f732dda74Tony Mak    private static final ComponentName PSTN_CONNECTION_SERVICE_COMPONENT =
1494c8f3c63b75ba080ab697b2e8e0f1e3f732dda74Tony Mak            new ComponentName("com.android.phone",
1504c8f3c63b75ba080ab697b2e8e0f1e3f732dda74Tony Mak                    "com.android.services.telephony.TelephonyConnectionService");
1514c8f3c63b75ba080ab697b2e8e0f1e3f732dda74Tony Mak
1527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
1537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Handler that tracks the connections and updates the value of the
1547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Mute settings for each connection as needed.
1557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
1567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static class ConnectionHandler extends Handler {
1577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        @Override
1587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        public void handleMessage(Message msg) {
1597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            switch (msg.what) {
160a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                case MSG_CHECK_STATUS_ANSWERCALL:
161a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                    FgRingCalls frC = (FgRingCalls) msg.obj;
162a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                    // wait for finishing disconnecting
163a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                    // before check the ringing call state
164a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                    if ((frC.fgCall != null) &&
165a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                        (frC.fgCall.getState() == Call.State.DISCONNECTING) &&
166a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                        (msg.arg1 < DISCONNECTING_POLLING_TIMES_LIMIT)) {
167a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                        Message retryMsg =
168a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                            mConnectionHandler.obtainMessage(MSG_CHECK_STATUS_ANSWERCALL);
169a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                        retryMsg.arg1 = 1 + msg.arg1;
170a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                        retryMsg.obj = msg.obj;
171a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                        mConnectionHandler.sendMessageDelayed(retryMsg,
172a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                            DISCONNECTING_POLLING_INTERVAL_MS);
173a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                    // since hangupActiveCall() also accepts the ringing call
174a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                    // check if the ringing call was already answered or not
175a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                    // only answer it when the call still is ringing
176a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                    } else if (frC.ringing.isRinging()) {
177a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                        if (msg.arg1 == DISCONNECTING_POLLING_TIMES_LIMIT) {
178a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                            Log.e(LOG_TAG, "DISCONNECTING time out");
179a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                        }
180a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                        answerCall(frC.ringing);
181a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                    }
182a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                    break;
1837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
1847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
1857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
1867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
1887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Register the ConnectionHandler with the phone, to receive connection events
1897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
1907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public static void initializeConnectionHandler(CallManager cm) {
1917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (mConnectionHandler == null) {
1927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            mConnectionHandler = new ConnectionHandler();
1937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
1947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // pass over cm as user.obj
1967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        cm.registerForPreciseCallStateChanged(mConnectionHandler, PHONE_STATE_CHANGED, cm);
1977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
1997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /** This class is never instantiated. */
2017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private PhoneUtils() {
2027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
2037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
2057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Answer the currently-ringing call.
2067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
2077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return true if we answered the call, or false if there wasn't
2087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *         actually a ringing incoming call, or some other error occurred.
2097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
2107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @see #answerAndEndHolding(CallManager, Call)
2117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @see #answerAndEndActive(CallManager, Call)
2127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
2137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /* package */ static boolean answerCall(Call ringingCall) {
2147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        log("answerCall(" + ringingCall + ")...");
2157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final PhoneGlobals app = PhoneGlobals.getInstance();
2167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final CallNotifier notifier = app.notifier;
2177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final Phone phone = ringingCall.getPhone();
2197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final boolean phoneIsCdma = (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA);
2207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        boolean answered = false;
2217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        IBluetoothHeadsetPhone btPhone = null;
2227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (phoneIsCdma) {
2247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // Stop any signalInfo tone being played when a Call waiting gets answered
2257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (ringingCall.getState() == Call.State.WAITING) {
2267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                notifier.stopSignalInfoTone();
2277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
2287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
2297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (ringingCall != null && ringingCall.isRinging()) {
2317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG) log("answerCall: call state = " + ringingCall.getState());
2327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            try {
2337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (phoneIsCdma) {
2347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    if (app.cdmaPhoneCallState.getCurrentCallState()
2357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            == CdmaPhoneCallState.PhoneCallState.IDLE) {
2367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        // This is the FIRST incoming call being answered.
2377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        // Set the Phone Call State to SINGLE_ACTIVE
2387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        app.cdmaPhoneCallState.setCurrentCallState(
2397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                CdmaPhoneCallState.PhoneCallState.SINGLE_ACTIVE);
2407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    } else {
2417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        // This is the CALL WAITING call being answered.
2427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        // Set the Phone Call State to CONF_CALL
2437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        app.cdmaPhoneCallState.setCurrentCallState(
2447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                CdmaPhoneCallState.PhoneCallState.CONF_CALL);
2457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        // Enable "Add Call" option after answering a Call Waiting as the user
2467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        // should be allowed to add another call in case one of the parties
2477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        // drops off
2487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        app.cdmaPhoneCallState.setAddCallMenuStateAfterCallWaiting(true);
24913fed9f2657f9bcc8c4b54783cf165cd4d7b57c1Santos Cordon                    }
2507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
2517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                final boolean isRealIncomingCall = isRealIncomingCall(ringingCall.getState());
2537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //if (DBG) log("sPhone.acceptCall");
2557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                app.mCM.acceptCall(ringingCall);
2567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                answered = true;
2577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                setAudioMode();
2597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            } catch (CallStateException ex) {
2607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Log.w(LOG_TAG, "answerCall: caught " + ex, ex);
2617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (phoneIsCdma) {
2637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // restore the cdmaPhoneCallState and btPhone.cdmaSetSecondCallState:
2647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    app.cdmaPhoneCallState.setCurrentCallState(
2657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            app.cdmaPhoneCallState.getPreviousCallState());
2667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    if (btPhone != null) {
2677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        try {
2687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            btPhone.cdmaSetSecondCallState(false);
2697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        } catch (RemoteException e) {
2707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            Log.e(LOG_TAG, Log.getStackTraceString(new Throwable()));
2717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        }
2727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    }
2737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
2747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
2757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
2767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return answered;
2777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
2787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
280de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon     * Hangs up all active calls.
281de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon     */
282de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon    static void hangupAllCalls(CallManager cm) {
283de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon        final Call ringing = cm.getFirstActiveRingingCall();
284de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon        final Call fg = cm.getActiveFgCall();
285de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon        final Call bg = cm.getFirstActiveBgCall();
286de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon
287de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon        // We go in reverse order, BG->FG->RINGING because hanging up a ringing call or an active
288de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon        // call can move a bg call to a fg call which would force us to loop over each call
289de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon        // several times.  This ordering works best to ensure we dont have any more calls.
290de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon        if (bg != null && !bg.isIdle()) {
291de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon            hangup(bg);
292de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon        }
293de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon        if (fg != null && !fg.isIdle()) {
294de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon            hangup(fg);
295de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon        }
296de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon        if (ringing != null && !ringing.isIdle()) {
297de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon            hangupRingingCall(fg);
298de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon        }
299de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon    }
300de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon
301de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon    /**
3027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Smart "hang up" helper method which hangs up exactly one connection,
3037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * based on the current Phone state, as follows:
3047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * <ul>
3057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * <li>If there's a ringing call, hang that up.
3067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * <li>Else if there's a foreground call, hang that up.
3077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * <li>Else if there's a background call, hang that up.
3087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * <li>Otherwise do nothing.
3097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * </ul>
3107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return true if we successfully hung up, or false
3117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *              if there were no active calls at all.
3127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
3137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static boolean hangup(CallManager cm) {
3147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        boolean hungup = false;
3157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Call ringing = cm.getFirstActiveRingingCall();
3167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Call fg = cm.getActiveFgCall();
3177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Call bg = cm.getFirstActiveBgCall();
3187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
3197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (!ringing.isIdle()) {
3207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            log("hangup(): hanging up ringing call");
3217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            hungup = hangupRingingCall(ringing);
3227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else if (!fg.isIdle()) {
3237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            log("hangup(): hanging up foreground call");
3247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            hungup = hangup(fg);
3257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else if (!bg.isIdle()) {
3267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            log("hangup(): hanging up background call");
3277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            hungup = hangup(bg);
3287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
3297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // No call to hang up!  This is unlikely in normal usage,
3307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // since the UI shouldn't be providing an "End call" button in
3317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // the first place.  (But it *can* happen, rarely, if an
3327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // active call happens to disconnect on its own right when the
3337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // user is trying to hang up..)
3347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            log("hangup(): no active call to hang up");
3357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
3367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("==> hungup = " + hungup);
3377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
3387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return hungup;
3397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
3407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
3417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static boolean hangupRingingCall(Call ringing) {
3427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("hangup ringing call");
3437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        int phoneType = ringing.getPhone().getPhoneType();
3447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Call.State state = ringing.getState();
3457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
3467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (state == Call.State.INCOMING) {
3477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // Regular incoming call (with no other active calls)
3487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            log("hangupRingingCall(): regular incoming call: hangup()");
3497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return hangup(ringing);
3507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
3517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // Unexpected state: the ringing call isn't INCOMING or
3527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // WAITING, so there's no reason to have called
3537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // hangupRingingCall() in the first place.
3547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // (Presumably the incoming call went away at the exact moment
3557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // we got here, so just do nothing.)
3567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Log.w(LOG_TAG, "hangupRingingCall: no INCOMING or WAITING call");
3577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return false;
3587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
3597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
3607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
3617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static boolean hangupActiveCall(Call foreground) {
3627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("hangup active call");
3637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return hangup(foreground);
3647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
3657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
3667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static boolean hangupHoldingCall(Call background) {
3677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("hangup holding call");
3687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return hangup(background);
3697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
3707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
3717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
3727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Used in CDMA phones to end the complete Call session
3737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param phone the Phone object.
3747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return true if *any* call was successfully hung up
3757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
3767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static boolean hangupRingingAndActive(Phone phone) {
3777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        boolean hungUpRingingCall = false;
3787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        boolean hungUpFgCall = false;
3797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Call ringingCall = phone.getRingingCall();
3807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Call fgCall = phone.getForegroundCall();
3817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
3827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Hang up any Ringing Call
3837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (!ringingCall.isIdle()) {
3847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            log("hangupRingingAndActive: Hang up Ringing Call");
3857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            hungUpRingingCall = hangupRingingCall(ringingCall);
3867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
3877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
3887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Hang up any Active Call
3897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (!fgCall.isIdle()) {
3907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            log("hangupRingingAndActive: Hang up Foreground Call");
3917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            hungUpFgCall = hangupActiveCall(fgCall);
3927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
3937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
3947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return hungUpRingingCall || hungUpFgCall;
3957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
3967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
3977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
3987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Trivial wrapper around Call.hangup(), except that we return a
3997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * boolean success code rather than throwing CallStateException on
4007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * failure.
4017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
4027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return true if the call was successfully hung up, or false
4037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *         if the call wasn't actually active.
4047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
4057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static boolean hangup(Call call) {
4067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        try {
4077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            CallManager cm = PhoneGlobals.getInstance().mCM;
4087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (call.getState() == Call.State.ACTIVE && cm.hasActiveBgCall()) {
4107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // handle foreground call hangup while there is background call
4117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                log("- hangup(Call): hangupForegroundResumeBackground...");
4127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                cm.hangupForegroundResumeBackground(cm.getFirstActiveBgCall());
4137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            } else {
4147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                log("- hangup(Call): regular hangup()...");
4157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                call.hangup();
4167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
4177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return true;
4187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } catch (CallStateException ex) {
4197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Log.e(LOG_TAG, "Call hangup: caught " + ex, ex);
4207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
4217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return false;
4237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
4247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
4267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Trivial wrapper around Connection.hangup(), except that we silently
4277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * do nothing (rather than throwing CallStateException) if the
4287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * connection wasn't actually active.
4297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
4307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static void hangup(Connection c) {
4317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        try {
4327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (c != null) {
4337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                c.hangup();
4347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
4357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } catch (CallStateException ex) {
4367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Log.w(LOG_TAG, "Connection hangup: caught " + ex, ex);
4377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
4387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
4397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static boolean answerAndEndHolding(CallManager cm, Call ringing) {
4417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("end holding & answer waiting: 1");
4427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (!hangupHoldingCall(cm.getFirstActiveBgCall())) {
4437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Log.e(LOG_TAG, "end holding failed!");
4447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return false;
4457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
4467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("end holding & answer waiting: 2");
4487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return answerCall(ringing);
4497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
4517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
4537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Answers the incoming call specified by "ringing", and ends the currently active phone call.
4547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
4557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * This method is useful when's there's an incoming call which we cannot manage with the
4567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * current call. e.g. when you are having a phone call with CDMA network and has received
4577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * a SIP call, then we won't expect our telephony can manage those phone calls simultaneously.
4587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Note that some types of network may allow multiple phone calls at once; GSM allows to hold
4597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * an ongoing phone call, so we don't need to end the active call. The caller of this method
4607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * needs to check if the network allows multiple phone calls or not.
4617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
4627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @see #answerCall(Call)
4637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @see InCallScreen#internalAnswerCall()
4647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
4657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /* package */ static boolean answerAndEndActive(CallManager cm, Call ringing) {
4667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("answerAndEndActive()...");
4677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Unlike the answerCall() method, we *don't* need to stop the
4697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // ringer or change audio modes here since the user is already
4707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // in-call, which means that the audio mode is already set
4717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // correctly, and that we wouldn't have started the ringer in the
4727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // first place.
4737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // hanging up the active call also accepts the waiting call
4757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // while active call and waiting call are from the same phone
4767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // i.e. both from GSM phone
477a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu        Call fgCall = cm.getActiveFgCall();
478a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu        if (!hangupActiveCall(fgCall)) {
4797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Log.w(LOG_TAG, "end active call failed!");
4807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return false;
4817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
4827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
483a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu        mConnectionHandler.removeMessages(MSG_CHECK_STATUS_ANSWERCALL);
484a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu        Message msg = mConnectionHandler.obtainMessage(MSG_CHECK_STATUS_ANSWERCALL);
485a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu        msg.arg1 = 1;
486a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu        msg.obj = new FgRingCalls(fgCall, ringing);
487a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu        mConnectionHandler.sendMessage(msg);
4887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return true;
4907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
4917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
4937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * For a CDMA phone, advance the call state upon making a new
4947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * outgoing call.
4957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
4967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * <pre>
4977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *   IDLE -> SINGLE_ACTIVE
4987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * or
4997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *   SINGLE_ACTIVE -> THRWAY_ACTIVE
5007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * </pre>
5017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param app The phone instance.
5027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
503ad1ed6d23c4a999a41bb73b8243009e32f96d7dfSantos Cordon    private static void updateCdmaCallStateOnNewOutgoingCall(PhoneGlobals app,
504ad1ed6d23c4a999a41bb73b8243009e32f96d7dfSantos Cordon            Connection connection) {
5057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (app.cdmaPhoneCallState.getCurrentCallState() ==
5067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            CdmaPhoneCallState.PhoneCallState.IDLE) {
5077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // This is the first outgoing call. Set the Phone Call State to ACTIVE
5087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            app.cdmaPhoneCallState.setCurrentCallState(
5097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                CdmaPhoneCallState.PhoneCallState.SINGLE_ACTIVE);
5107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
5117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // This is the second outgoing call. Set the Phone Call State to 3WAY
5127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            app.cdmaPhoneCallState.setCurrentCallState(
5137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE);
514ad1ed6d23c4a999a41bb73b8243009e32f96d7dfSantos Cordon
515da120f4e3d32ca97c5b4c21d6c505d834a29ab8dSantos Cordon            // TODO: Remove this code.
51623d9ed758fbe78e4afd4067e6845bcaf3387bca7Sailesh Nepal            //app.getCallModeler().setCdmaOutgoing3WayCall(connection);
5177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
5187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
5197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
52169a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon     * @see placeCall below
52269a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon     */
52369a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon    public static int placeCall(Context context, Phone phone, String number, Uri contactRef,
52469a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon            boolean isEmergencyCall) {
52569a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon        return placeCall(context, phone, number, contactRef, isEmergencyCall,
52669a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon                CallGatewayManager.EMPTY_INFO, null);
52769a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon    }
52869a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon
52969a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon    /**
5307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Dial the number using the phone passed in.
5317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
5327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * If the connection is establised, this method issues a sync call
5337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * that may block to query the caller info.
5347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * TODO: Change the logic to use the async query.
5357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
5367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param context To perform the CallerInfo query.
5377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param phone the Phone object.
5387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param number to be dialed as requested by the user. This is
5397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * NOT the phone number to connect to. It is used only to build the
5407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * call card and to update the call log. See above for restrictions.
5417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param contactRef that triggered the call. Typically a 'tel:'
5427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * uri but can also be a 'content://contacts' one.
5437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param isEmergencyCall indicates that whether or not this is an
5447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * emergency call
5457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param gatewayUri Is the address used to setup the connection, null
5467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * if not using a gateway
54769a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon     * @param callGateway Class for setting gateway data on a successful call.
5487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
5497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return either CALL_STATUS_DIALED or CALL_STATUS_FAILED
5507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
55169a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon    public static int placeCall(Context context, Phone phone, String number, Uri contactRef,
55269a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon            boolean isEmergencyCall, RawGatewayInfo gatewayInfo, CallGatewayManager callGateway) {
55369a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon        final Uri gatewayUri = gatewayInfo.gatewayUri;
55469a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon
5557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (VDBG) {
5567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            log("placeCall()... number: '" + number + "'"
5577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    + ", GW:'" + gatewayUri + "'"
5587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    + ", contactRef:" + contactRef
5597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    + ", isEmergencyCall: " + isEmergencyCall);
5607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
5617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            log("placeCall()... number: " + toLogSafePhoneNumber(number)
5627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    + ", GW: " + (gatewayUri != null ? "non-null" : "null")
5637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    + ", emergency? " + isEmergencyCall);
5647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
5657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final PhoneGlobals app = PhoneGlobals.getInstance();
5667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        boolean useGateway = false;
5687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (null != gatewayUri &&
5697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            !isEmergencyCall &&
5707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            PhoneUtils.isRoutableViaGateway(number)) {  // Filter out MMI, OTA and other codes.
5717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            useGateway = true;
5727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
5737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        int status = CALL_STATUS_DIALED;
5757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Connection connection;
5767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        String numberToDial;
5777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (useGateway) {
5787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // TODO: 'tel' should be a constant defined in framework base
5797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // somewhere (it is in webkit.)
580137458b4bf3516941483e59c123c22cbee27ed43Jay Shrauner            if (null == gatewayUri || !PhoneAccount.SCHEME_TEL.equals(gatewayUri.getScheme())) {
5817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Log.e(LOG_TAG, "Unsupported URL:" + gatewayUri);
5827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                return CALL_STATUS_FAILED;
5837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
5847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // We can use getSchemeSpecificPart because we don't allow #
5867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // in the gateway numbers (treated a fragment delim.) However
5877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // if we allow more complex gateway numbers sequence (with
5887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // passwords or whatnot) that use #, this may break.
5897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // TODO: Need to support MMI codes.
5907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            numberToDial = gatewayUri.getSchemeSpecificPart();
5917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
5927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            numberToDial = number;
5937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
5947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Remember if the phone state was in IDLE state before this call.
5967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // After calling CallManager#dial(), getState() will return different state.
5977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final boolean initiallyIdle = app.mCM.getState() == PhoneConstants.State.IDLE;
5987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        try {
600c6514358fdf6060233141140a5cc08579c55b8eaTyler Gunn            connection = app.mCM.dial(phone, numberToDial, VideoProfile.STATE_AUDIO_ONLY);
6017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } catch (CallStateException ex) {
6027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // CallStateException means a new outgoing call is not currently
6037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // possible: either no more call slots exist, or there's another
6047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // call already in the process of dialing or ringing.
6057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Log.w(LOG_TAG, "Exception from app.mCM.dial()", ex);
6067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return CALL_STATUS_FAILED;
6077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
6087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // Note that it's possible for CallManager.dial() to return
6097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // null *without* throwing an exception; that indicates that
6107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // we dialed an MMI (see below).
6117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
6127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
6137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        int phoneType = phone.getPhoneType();
6147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
6157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // On GSM phones, null is returned for MMI codes
6167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (null == connection) {
617f77a3397cb022cb6aa8e7e72a5b14ba29a99563fSantos Cordon            status = CALL_STATUS_FAILED;
6187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
61910f1c6a97074b981b08bb804a3568c17ec3890a5Tyler Gunn            // Now that the call is successful, we can save the gateway info for the call
62010f1c6a97074b981b08bb804a3568c17ec3890a5Tyler Gunn            if (callGateway != null) {
62110f1c6a97074b981b08bb804a3568c17ec3890a5Tyler Gunn                callGateway.setGatewayInfoForConnection(connection, gatewayInfo);
62210f1c6a97074b981b08bb804a3568c17ec3890a5Tyler Gunn            }
62310f1c6a97074b981b08bb804a3568c17ec3890a5Tyler Gunn
6247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
625ad1ed6d23c4a999a41bb73b8243009e32f96d7dfSantos Cordon                updateCdmaCallStateOnNewOutgoingCall(app, connection);
6267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
6277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
6287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (gatewayUri == null) {
6297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // phone.dial() succeeded: we're now in a normal phone call.
6307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // attach the URI to the CallerInfo Object if it is there,
6317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // otherwise just attach the Uri Reference.
6327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // if the uri does not have a "content" scheme, then we treat
6337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // it as if it does NOT have a unique reference.
6347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                String content = context.getContentResolver().SCHEME_CONTENT;
6357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if ((contactRef != null) && (contactRef.getScheme().equals(content))) {
6367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    Object userDataObject = connection.getUserData();
6377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    if (userDataObject == null) {
6387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        connection.setUserData(contactRef);
6397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    } else {
6407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        // TODO: This branch is dead code, we have
6417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        // just created the connection which has
6427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        // no user data (null) by default.
6437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        if (userDataObject instanceof CallerInfo) {
6447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        ((CallerInfo) userDataObject).contactRefUri = contactRef;
6457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        } else {
6467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        ((CallerInfoToken) userDataObject).currentInfo.contactRefUri =
6477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            contactRef;
6487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        }
6497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    }
6507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
6517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
652c264cba0b6ea81b3f741d9c41a0a50b7ffd19220Santos Cordon
653e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng            startGetCallerInfo(context, connection, null, null, gatewayInfo);
654e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng
6557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            setAudioMode();
6567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
6577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
6587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return status;
6597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
6607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
6617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /* package */ static String toLogSafePhoneNumber(String number) {
6627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // For unknown number, log empty string.
6637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (number == null) {
6647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return "";
6657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
6667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
6677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (VDBG) {
6687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // When VDBG is true we emit PII.
6697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return number;
6707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
6717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
6727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Do exactly same thing as Uri#toSafeString() does, which will enable us to compare
6737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // sanitized phone numbers.
6747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        StringBuilder builder = new StringBuilder();
6757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        for (int i = 0; i < number.length(); i++) {
6767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            char c = number.charAt(i);
6777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (c == '-' || c == '@' || c == '.') {
6787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                builder.append(c);
6797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            } else {
6807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                builder.append('x');
6817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
6827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
6837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return builder.toString();
6847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
6857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
6867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
6877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Wrapper function to control when to send an empty Flash command to the network.
6887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Mainly needed for CDMA networks, such as scenarios when we need to send a blank flash
6897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * to the network prior to placing a 3-way call for it to be successful.
6907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
6917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static void sendEmptyFlash(Phone phone) {
6927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {
6937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Call fgCall = phone.getForegroundCall();
6947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (fgCall.getState() == Call.State.ACTIVE) {
6957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // Send the empty flash
6967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (DBG) Log.d(LOG_TAG, "onReceive: (CDMA) sending empty flash to network");
6977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                switchHoldingAndActive(phone.getBackgroundCall());
6987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
6997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
7007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
7017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
70236ebb0d4d04346a367b7a54b178ab4f78696e95cGabriel Peal    static void swap() {
70336ebb0d4d04346a367b7a54b178ab4f78696e95cGabriel Peal        final PhoneGlobals mApp = PhoneGlobals.getInstance();
70436ebb0d4d04346a367b7a54b178ab4f78696e95cGabriel Peal        if (!okToSwapCalls(mApp.mCM)) {
70536ebb0d4d04346a367b7a54b178ab4f78696e95cGabriel Peal            // TODO: throw an error instead?
70636ebb0d4d04346a367b7a54b178ab4f78696e95cGabriel Peal            return;
70736ebb0d4d04346a367b7a54b178ab4f78696e95cGabriel Peal        }
70836ebb0d4d04346a367b7a54b178ab4f78696e95cGabriel Peal
70936ebb0d4d04346a367b7a54b178ab4f78696e95cGabriel Peal        // Swap the fg and bg calls.
71036ebb0d4d04346a367b7a54b178ab4f78696e95cGabriel Peal        // In the future we may provide some way for user to choose among
71136ebb0d4d04346a367b7a54b178ab4f78696e95cGabriel Peal        // multiple background calls, for now, always act on the first background call.
71236ebb0d4d04346a367b7a54b178ab4f78696e95cGabriel Peal        PhoneUtils.switchHoldingAndActive(mApp.mCM.getFirstActiveBgCall());
71336ebb0d4d04346a367b7a54b178ab4f78696e95cGabriel Peal    }
71436ebb0d4d04346a367b7a54b178ab4f78696e95cGabriel Peal
7157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
7167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param heldCall is the background call want to be swapped
7177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
7187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static void switchHoldingAndActive(Call heldCall) {
7197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        log("switchHoldingAndActive()...");
7207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        try {
7217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            CallManager cm = PhoneGlobals.getInstance().mCM;
7227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (heldCall.isIdle()) {
7237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // no heldCall, so it is to hold active call
7247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                cm.switchHoldingAndActive(cm.getFgPhone().getBackgroundCall());
7257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            } else {
7267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // has particular heldCall, so to switch
7277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                cm.switchHoldingAndActive(heldCall);
7287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
7297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            setAudioMode(cm);
7307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } catch (CallStateException ex) {
7317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Log.w(LOG_TAG, "switchHoldingAndActive: caught " + ex, ex);
7327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
7337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
7347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
7357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static void mergeCalls() {
7367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        mergeCalls(PhoneGlobals.getInstance().mCM);
7377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
7387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
7397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static void mergeCalls(CallManager cm) {
7407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        int phoneType = cm.getFgPhone().getPhoneType();
7417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
7427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            log("mergeCalls(): CDMA...");
7437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            PhoneGlobals app = PhoneGlobals.getInstance();
7447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (app.cdmaPhoneCallState.getCurrentCallState()
7457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    == CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE) {
7467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // Set the Phone Call State to conference
7477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                app.cdmaPhoneCallState.setCurrentCallState(
7487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        CdmaPhoneCallState.PhoneCallState.CONF_CALL);
7497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
7507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // Send flash cmd
7517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // TODO: Need to change the call from switchHoldingAndActive to
7527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // something meaningful as we are not actually trying to swap calls but
7537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // instead are merging two calls by sending a Flash command.
7547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                log("- sending flash...");
7557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                switchHoldingAndActive(cm.getFirstActiveBgCall());
7567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
7577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
7587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            try {
7597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                log("mergeCalls(): calling cm.conference()...");
7607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                cm.conference(cm.getFirstActiveBgCall());
7617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            } catch (CallStateException ex) {
7627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Log.w(LOG_TAG, "mergeCalls: caught " + ex, ex);
7637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
7647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
7657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
7667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
7677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static void separateCall(Connection c) {
7687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        try {
7697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG) log("separateCall: " + toLogSafePhoneNumber(c.getAddress()));
7707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            c.separate();
7717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } catch (CallStateException ex) {
7727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Log.w(LOG_TAG, "separateCall: caught " + ex, ex);
7737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
7747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
7757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
7767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
7777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Handle the MMIInitiate message and put up an alert that lets
7787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * the user cancel the operation, if applicable.
7797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
7807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param context context to get strings.
7817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param mmiCode the MmiCode object being started.
7827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param buttonCallbackMessage message to post when button is clicked.
7837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param previousAlert a previous alert used in this activity.
7847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return the dialog handle
7857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
7867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static Dialog displayMMIInitiate(Context context,
7877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                          MmiCode mmiCode,
7887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                          Message buttonCallbackMessage,
7897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                          Dialog previousAlert) {
79013fe249b0ba05e6652a4ce2d5271be5b8f3a3672Tyler Gunn        log("displayMMIInitiate: " + android.telecom.Log.pii(mmiCode.toString()));
7917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (previousAlert != null) {
7927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            previousAlert.dismiss();
7937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
7947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
7957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // The UI paradigm we are using now requests that all dialogs have
7967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // user interaction, and that any other messages to the user should
7977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // be by way of Toasts.
7987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //
7997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // In adhering to this request, all MMI initiating "OK" dialogs
8007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // (non-cancelable MMIs) that end up being closed when the MMI
8017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // completes (thereby showing a completion dialog) are being
8027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // replaced with Toasts.
8037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //
8047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // As a side effect, moving to Toasts for the non-cancelable MMIs
8057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // also means that buttonCallbackMessage (which was tied into "OK")
8067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // is no longer invokable for these dialogs.  This is not a problem
8077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // since the only callback messages we supported were for cancelable
8087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // MMIs anyway.
8097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //
8107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // A cancelable MMI is really just a USSD request. The term
8117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // "cancelable" here means that we can cancel the request when the
8127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // system prompts us for a response, NOT while the network is
8137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // processing the MMI request.  Any request to cancel a USSD while
8147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // the network is NOT ready for a response may be ignored.
8157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //
8167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // With this in mind, we replace the cancelable alert dialog with
8177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // a progress dialog, displayed until we receive a request from
8187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // the the network.  For more information, please see the comments
8197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // in the displayMMIComplete() method below.
8207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //
8217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Anything that is NOT a USSD request is a normal MMI request,
8227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // which will bring up a toast (desribed above).
8237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
8247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        boolean isCancelable = (mmiCode != null) && mmiCode.isCancelable();
8257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
8267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (!isCancelable) {
82713fe249b0ba05e6652a4ce2d5271be5b8f3a3672Tyler Gunn            log("displayMMIInitiate: not a USSD code, displaying status toast.");
8287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            CharSequence text = context.getText(R.string.mmiStarted);
8297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Toast.makeText(context, text, Toast.LENGTH_SHORT)
8307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                .show();
8317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return null;
8327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
83313fe249b0ba05e6652a4ce2d5271be5b8f3a3672Tyler Gunn            log("displayMMIInitiate: running USSD code, displaying intermediate progress.");
8347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
8357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // create the indeterminate progress dialog and display it.
836779841a270cfd831df58eb7e9b3d5ae0fd4211daAlex Hills            ProgressDialog pd = new ProgressDialog(context, THEME);
8377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            pd.setMessage(context.getText(R.string.ussdRunning));
8387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            pd.setCancelable(false);
8397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            pd.setIndeterminate(true);
8407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            pd.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
8417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
8427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            pd.show();
8437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
8447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return pd;
8457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
8467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
8477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
8487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
8497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
8507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Handle the MMIComplete message and fire off an intent to display
8517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * the message.
8527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
8537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param context context to get strings.
8547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param mmiCode MMI result.
8557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param previousAlert a previous alert used in this activity.
8567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
8577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static void displayMMIComplete(final Phone phone, Context context, final MmiCode mmiCode,
8587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Message dismissCallbackMessage,
8597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            AlertDialog previousAlert) {
8607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final PhoneGlobals app = PhoneGlobals.getInstance();
8617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        CharSequence text;
8627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        int title = 0;  // title for the progress dialog, if needed.
8637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        MmiCode.State state = mmiCode.getState();
8647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
86513fe249b0ba05e6652a4ce2d5271be5b8f3a3672Tyler Gunn        log("displayMMIComplete: state=" + state);
8667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
8677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        switch (state) {
8687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            case PENDING:
8697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // USSD code asking for feedback from user.
8707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                text = mmiCode.getMessage();
87113fe249b0ba05e6652a4ce2d5271be5b8f3a3672Tyler Gunn                log("displayMMIComplete: using text from PENDING MMI message: '" + text + "'");
8727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                break;
8737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            case CANCELLED:
8747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                text = null;
8757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                break;
8767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            case COMPLETE:
8777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (app.getPUKEntryActivity() != null) {
8787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // if an attempt to unPUK the device was made, we specify
8797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // the title and the message here.
8807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    title = com.android.internal.R.string.PinMmi;
8817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    text = context.getText(R.string.puk_unlocked);
8827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    break;
8837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
8847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // All other conditions for the COMPLETE mmi state will cause
8857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // the case to fall through to message logic in common with
8867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // the FAILED case.
8877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
8887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            case FAILED:
8897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                text = mmiCode.getMessage();
89013fe249b0ba05e6652a4ce2d5271be5b8f3a3672Tyler Gunn                log("displayMMIComplete (failed): using text from MMI message: '" + text + "'");
8917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                break;
8927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            default:
8937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                throw new IllegalStateException("Unexpected MmiCode state: " + state);
8947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
8957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
8967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (previousAlert != null) {
8977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            previousAlert.dismiss();
8987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
8997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
9007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Check to see if a UI exists for the PUK activation.  If it does
9017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // exist, then it indicates that we're trying to unblock the PUK.
9027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if ((app.getPUKEntryActivity() != null) && (state == MmiCode.State.COMPLETE)) {
9037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG) log("displaying PUK unblocking progress dialog.");
9047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
9057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // create the progress dialog, make sure the flags and type are
9067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // set correctly.
907779841a270cfd831df58eb7e9b3d5ae0fd4211daAlex Hills            ProgressDialog pd = new ProgressDialog(app, THEME);
9087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            pd.setTitle(title);
9097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            pd.setMessage(text);
9107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            pd.setCancelable(false);
9117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            pd.setIndeterminate(true);
9127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            pd.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
9137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            pd.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
9147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
9157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // display the dialog
9167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            pd.show();
9177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
9187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // indicate to the Phone app that the progress dialog has
9197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // been assigned for the PUK unlock / SIM READY process.
9207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            app.setPukEntryProgressDialog(pd);
9217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
9227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
9237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // In case of failure to unlock, we'll need to reset the
9247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // PUK unlock activity, so that the user may try again.
9257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (app.getPUKEntryActivity() != null) {
9267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                app.setPukEntryActivity(null);
9277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
9287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
9297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // A USSD in a pending state means that it is still
9307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // interacting with the user.
9317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (state != MmiCode.State.PENDING) {
93213fe249b0ba05e6652a4ce2d5271be5b8f3a3672Tyler Gunn                log("displayMMIComplete: MMI code has finished running.");
9337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
93413fe249b0ba05e6652a4ce2d5271be5b8f3a3672Tyler Gunn                log("displayMMIComplete: Extended NW displayMMIInitiate (" + text + ")");
9357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (text == null || text.length() == 0)
9367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    return;
9377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
9387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // displaying system alert dialog on the screen instead of
9397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // using another activity to display the message.  This
9407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // places the message at the forefront of the UI.
94137abbab24baec145cdf995693be96cd7162b0c06Etan Cohen
94237abbab24baec145cdf995693be96cd7162b0c06Etan Cohen                if (sUssdDialog == null) {
943e0f2b791135a88de7930e4339686fd5b79e53a9fYorke Lee                    sUssdDialog = new AlertDialog.Builder(context, THEME)
94437abbab24baec145cdf995693be96cd7162b0c06Etan Cohen                            .setPositiveButton(R.string.ok, null)
94537abbab24baec145cdf995693be96cd7162b0c06Etan Cohen                            .setCancelable(true)
94637abbab24baec145cdf995693be96cd7162b0c06Etan Cohen                            .setOnDismissListener(new DialogInterface.OnDismissListener() {
94737abbab24baec145cdf995693be96cd7162b0c06Etan Cohen                                @Override
94837abbab24baec145cdf995693be96cd7162b0c06Etan Cohen                                public void onDismiss(DialogInterface dialog) {
94937abbab24baec145cdf995693be96cd7162b0c06Etan Cohen                                    sUssdMsg.setLength(0);
95037abbab24baec145cdf995693be96cd7162b0c06Etan Cohen                                }
95137abbab24baec145cdf995693be96cd7162b0c06Etan Cohen                            })
95237abbab24baec145cdf995693be96cd7162b0c06Etan Cohen                            .create();
95337abbab24baec145cdf995693be96cd7162b0c06Etan Cohen
95437abbab24baec145cdf995693be96cd7162b0c06Etan Cohen                    sUssdDialog.getWindow().setType(
9552eefb2bb91cbc3c7d2ce1170ca1043b834ad394eBrad Ebinger                            WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
95637abbab24baec145cdf995693be96cd7162b0c06Etan Cohen                    sUssdDialog.getWindow().addFlags(
95737abbab24baec145cdf995693be96cd7162b0c06Etan Cohen                            WindowManager.LayoutParams.FLAG_DIM_BEHIND);
95837abbab24baec145cdf995693be96cd7162b0c06Etan Cohen                }
95937abbab24baec145cdf995693be96cd7162b0c06Etan Cohen                if (sUssdMsg.length() != 0) {
96037abbab24baec145cdf995693be96cd7162b0c06Etan Cohen                    sUssdMsg
96137abbab24baec145cdf995693be96cd7162b0c06Etan Cohen                            .insert(0, "\n")
96237abbab24baec145cdf995693be96cd7162b0c06Etan Cohen                            .insert(0, app.getResources().getString(R.string.ussd_dialog_sep))
96337abbab24baec145cdf995693be96cd7162b0c06Etan Cohen                            .insert(0, "\n");
96437abbab24baec145cdf995693be96cd7162b0c06Etan Cohen                }
96537abbab24baec145cdf995693be96cd7162b0c06Etan Cohen                sUssdMsg.insert(0, text);
96637abbab24baec145cdf995693be96cd7162b0c06Etan Cohen                sUssdDialog.setMessage(sUssdMsg.toString());
96737abbab24baec145cdf995693be96cd7162b0c06Etan Cohen                sUssdDialog.show();
9687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            } else {
96913fe249b0ba05e6652a4ce2d5271be5b8f3a3672Tyler Gunn                log("displayMMIComplete: USSD code has requested user input. Constructing input "
97013fe249b0ba05e6652a4ce2d5271be5b8f3a3672Tyler Gunn                        + "dialog.");
9717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
9727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // USSD MMI code that is interacting with the user.  The
9737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // basic set of steps is this:
9747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //   1. User enters a USSD request
9757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //   2. We recognize the request and displayMMIInitiate
9767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //      (above) creates a progress dialog.
9777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //   3. Request returns and we get a PENDING or COMPLETE
9787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //      message.
9797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //   4. These MMI messages are caught in the PhoneApp
9807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //      (onMMIComplete) and the InCallScreen
9817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //      (mHandler.handleMessage) which bring up this dialog
9827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //      and closes the original progress dialog,
9837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //      respectively.
9847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //   5. If the message is anything other than PENDING,
9857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //      we are done, and the alert dialog (directly above)
9867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //      displays the outcome.
9877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //   6. If the network is requesting more information from
9887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //      the user, the MMI will be in a PENDING state, and
9897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //      we display this dialog with the message.
9907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //   7. User input, or cancel requests result in a return
9917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //      to step 1.  Keep in mind that this is the only
9927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //      time that a USSD should be canceled.
9937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
9947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // inflate the layout with the scrolling text area for the dialog.
995b3ee4dc3dd39ebe765ebe6b535b3900bb95813d8Andrew Lee                ContextThemeWrapper contextThemeWrapper =
996b3ee4dc3dd39ebe765ebe6b535b3900bb95813d8Andrew Lee                        new ContextThemeWrapper(context, R.style.DialerAlertDialogTheme);
997b3ee4dc3dd39ebe765ebe6b535b3900bb95813d8Andrew Lee                LayoutInflater inflater = (LayoutInflater) contextThemeWrapper.getSystemService(
9987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        Context.LAYOUT_INFLATER_SERVICE);
9997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                View dialogView = inflater.inflate(R.layout.dialog_ussd_response, null);
10007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
10017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // get the input field.
10027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                final EditText inputText = (EditText) dialogView.findViewById(R.id.input_field);
10037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
10047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // specify the dialog's click listener, with SEND and CANCEL logic.
10057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                final DialogInterface.OnClickListener mUSSDDialogListener =
10067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    new DialogInterface.OnClickListener() {
10077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        public void onClick(DialogInterface dialog, int whichButton) {
10087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            switch (whichButton) {
10097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                case DialogInterface.BUTTON_POSITIVE:
10107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                    // As per spec 24.080, valid length of ussd string
10117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                    // is 1 - 160. If length is out of the range then
10127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                    // display toast message & Cancel MMI operation.
10137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                    if (inputText.length() < MIN_USSD_LEN
10147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                            || inputText.length() > MAX_USSD_LEN) {
10157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                        Toast.makeText(app,
10167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                                app.getResources().getString(R.string.enter_input,
10177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                                MIN_USSD_LEN, MAX_USSD_LEN),
10187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                                Toast.LENGTH_LONG).show();
10197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                        if (mmiCode.isCancelable()) {
10207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                            mmiCode.cancel();
10217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                        }
10227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                    } else {
10237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                        phone.sendUssdResponse(inputText.getText().toString());
10247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                    }
10257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                    break;
10267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                case DialogInterface.BUTTON_NEGATIVE:
10277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                    if (mmiCode.isCancelable()) {
10287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                        mmiCode.cancel();
10297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                    }
10307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                    break;
10317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            }
10327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        }
10337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    };
10347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
10357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // build the dialog
1036b3ee4dc3dd39ebe765ebe6b535b3900bb95813d8Andrew Lee                final AlertDialog newDialog = new AlertDialog.Builder(contextThemeWrapper)
10377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        .setMessage(text)
10387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        .setView(dialogView)
10397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        .setPositiveButton(R.string.send_button, mUSSDDialogListener)
10407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        .setNegativeButton(R.string.cancel, mUSSDDialogListener)
10417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        .setCancelable(false)
10427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        .create();
10437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
10447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // attach the key listener to the dialog's input field and make
10457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // sure focus is set.
10467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                final View.OnKeyListener mUSSDDialogInputListener =
10477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    new View.OnKeyListener() {
10487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        public boolean onKey(View v, int keyCode, KeyEvent event) {
10497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            switch (keyCode) {
10507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                case KeyEvent.KEYCODE_CALL:
10517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                case KeyEvent.KEYCODE_ENTER:
10527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                    if(event.getAction() == KeyEvent.ACTION_DOWN) {
10537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                        phone.sendUssdResponse(inputText.getText().toString());
10547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                        newDialog.dismiss();
10557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                    }
10567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                    return true;
10577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            }
10587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            return false;
10597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        }
10607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    };
10617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                inputText.setOnKeyListener(mUSSDDialogInputListener);
10627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                inputText.requestFocus();
10637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
10647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // set the window properties of the dialog
10657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                newDialog.getWindow().setType(
10667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
10677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                newDialog.getWindow().addFlags(
10687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        WindowManager.LayoutParams.FLAG_DIM_BEHIND);
10697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
10707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // now show the dialog!
10717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                newDialog.show();
1072b3ee4dc3dd39ebe765ebe6b535b3900bb95813d8Andrew Lee
1073b3ee4dc3dd39ebe765ebe6b535b3900bb95813d8Andrew Lee                newDialog.getButton(DialogInterface.BUTTON_POSITIVE)
1074b3ee4dc3dd39ebe765ebe6b535b3900bb95813d8Andrew Lee                        .setTextColor(context.getResources().getColor(R.color.dialer_theme_color));
1075b3ee4dc3dd39ebe765ebe6b535b3900bb95813d8Andrew Lee                newDialog.getButton(DialogInterface.BUTTON_NEGATIVE)
1076b3ee4dc3dd39ebe765ebe6b535b3900bb95813d8Andrew Lee                        .setTextColor(context.getResources().getColor(R.color.dialer_theme_color));
10777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
10787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
10797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
10807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
10817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
10827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Cancels the current pending MMI operation, if applicable.
10837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return true if we canceled an MMI operation, or false
10847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *         if the current pending MMI wasn't cancelable
10857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *         or if there was no current pending MMI at all.
10867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
10877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @see displayMMIInitiate
10887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
10897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static boolean cancelMmiCode(Phone phone) {
10907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        List<? extends MmiCode> pendingMmis = phone.getPendingMmiCodes();
10917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        int count = pendingMmis.size();
10927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("cancelMmiCode: num pending MMIs = " + count);
10937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
10947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        boolean canceled = false;
10957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (count > 0) {
10967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // assume that we only have one pending MMI operation active at a time.
10977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // I don't think it's possible to enter multiple MMI codes concurrently
10987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // in the phone UI, because during the MMI operation, an Alert panel
10997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // is displayed, which prevents more MMI code from being entered.
11007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            MmiCode mmiCode = pendingMmis.get(0);
11017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (mmiCode.isCancelable()) {
11027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                mmiCode.cancel();
11037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                canceled = true;
11047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
11057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
11067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return canceled;
11077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
11087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
11097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public static class VoiceMailNumberMissingException extends Exception {
11107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        VoiceMailNumberMissingException() {
11117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            super();
11127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
11137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
11147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        VoiceMailNumberMissingException(String msg) {
11157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            super(msg);
11167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
11177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
11187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
11197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
11207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Given an Intent (which is presumably the ACTION_CALL intent that
11217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * initiated this outgoing call), figure out the actual phone number we
11227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * should dial.
11237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
11247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Note that the returned "number" may actually be a SIP address,
11257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * if the specified intent contains a sip: URI.
11267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
11277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * This method is basically a wrapper around PhoneUtils.getNumberFromIntent(),
11287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * except it's also aware of the EXTRA_ACTUAL_NUMBER_TO_DIAL extra.
11297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * (That extra, if present, tells us the exact string to pass down to the
11307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * telephony layer.  It's guaranteed to be safe to dial: it's either a PSTN
11317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * phone number with separators and keypad letters stripped out, or a raw
11327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * unencoded SIP address.)
11337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
11347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return the phone number corresponding to the specified Intent, or null
11357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *   if the Intent has no action or if the intent's data is malformed or
11367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *   missing.
11377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
11387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @throws VoiceMailNumberMissingException if the intent
11397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *   contains a "voicemail" URI, but there's no voicemail
11407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *   number configured on the device.
11417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
11427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public static String getInitialNumber(Intent intent)
11437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            throws PhoneUtils.VoiceMailNumberMissingException {
11447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("getInitialNumber(): " + intent);
11457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
11467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        String action = intent.getAction();
11477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (TextUtils.isEmpty(action)) {
11487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return null;
11497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
11507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
11517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // If the EXTRA_ACTUAL_NUMBER_TO_DIAL extra is present, get the phone
11527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // number from there.  (That extra takes precedence over the actual data
11537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // included in the intent.)
11547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (intent.hasExtra(OutgoingCallBroadcaster.EXTRA_ACTUAL_NUMBER_TO_DIAL)) {
11557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            String actualNumberToDial =
11567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    intent.getStringExtra(OutgoingCallBroadcaster.EXTRA_ACTUAL_NUMBER_TO_DIAL);
11577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG) {
11587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                log("==> got EXTRA_ACTUAL_NUMBER_TO_DIAL; returning '"
11597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        + toLogSafePhoneNumber(actualNumberToDial) + "'");
11607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
11617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return actualNumberToDial;
11627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
11637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
11647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return getNumberFromIntent(PhoneGlobals.getInstance(), intent);
11657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
11667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
11677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
11687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Gets the phone number to be called from an intent.  Requires a Context
11697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * to access the contacts database, and a Phone to access the voicemail
11707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * number.
11717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
11727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * <p>If <code>phone</code> is <code>null</code>, the function will return
11737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * <code>null</code> for <code>voicemail:</code> URIs;
11747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * if <code>context</code> is <code>null</code>, the function will return
11757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * <code>null</code> for person/phone URIs.</p>
11767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
11777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * <p>If the intent contains a <code>sip:</code> URI, the returned
11787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * "number" is actually the SIP address.
11797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
11807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param context a context to use (or
11817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param intent the intent
11827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
11837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @throws VoiceMailNumberMissingException if <code>intent</code> contains
11847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *         a <code>voicemail:</code> URI, but <code>phone</code> does not
11857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *         have a voicemail number set.
11867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
11877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return the phone number (or SIP address) that would be called by the intent,
11887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *         or <code>null</code> if the number cannot be found.
11897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
11907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static String getNumberFromIntent(Context context, Intent intent)
11917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            throws VoiceMailNumberMissingException {
11927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Uri uri = intent.getData();
11937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        String scheme = uri.getScheme();
11947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
11957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // The sip: scheme is simple: just treat the rest of the URI as a
11967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // SIP address.
1197137458b4bf3516941483e59c123c22cbee27ed43Jay Shrauner        if (PhoneAccount.SCHEME_SIP.equals(scheme)) {
11987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return uri.getSchemeSpecificPart();
11997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
12007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
12017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Otherwise, let PhoneNumberUtils.getNumberFromIntent() handle
12027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // the other cases (i.e. tel: and voicemail: and contact: URIs.)
12037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
12047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final String number = PhoneNumberUtils.getNumberFromIntent(intent, context);
12057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
12067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Check for a voicemail-dialing request.  If the voicemail number is
12077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // empty, throw a VoiceMailNumberMissingException.
1208137458b4bf3516941483e59c123c22cbee27ed43Jay Shrauner        if (PhoneAccount.SCHEME_VOICEMAIL.equals(scheme) &&
12097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                (number == null || TextUtils.isEmpty(number)))
12107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            throw new VoiceMailNumberMissingException();
12117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
12127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return number;
12137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
12147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
12157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
12167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Returns the caller-id info corresponding to the specified Connection.
12177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * (This is just a simple wrapper around CallerInfo.getCallerInfo(): we
12187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * extract a phone number from the specified Connection, and feed that
12197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * number into CallerInfo.getCallerInfo().)
12207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
12217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * The returned CallerInfo may be null in certain error cases, like if the
12227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * specified Connection was null, or if we weren't able to get a valid
12237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * phone number from the Connection.
12247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
12257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Finally, if the getCallerInfo() call did succeed, we save the resulting
12267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * CallerInfo object in the "userData" field of the Connection.
12277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
12287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * NOTE: This API should be avoided, with preference given to the
12297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * asynchronous startGetCallerInfo API.
12307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
12317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static CallerInfo getCallerInfo(Context context, Connection c) {
12327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        CallerInfo info = null;
12337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
12347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (c != null) {
12357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            //See if there is a URI attached.  If there is, this means
12367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            //that there is no CallerInfo queried yet, so we'll need to
12377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            //replace the URI with a full CallerInfo object.
12387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Object userDataObject = c.getUserData();
12397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (userDataObject instanceof Uri) {
12407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                info = CallerInfo.getCallerInfo(context, (Uri) userDataObject);
12417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (info != null) {
12427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    c.setUserData(info);
12437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
12447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            } else {
12457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (userDataObject instanceof CallerInfoToken) {
12467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    //temporary result, while query is running
12477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    info = ((CallerInfoToken) userDataObject).currentInfo;
12487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                } else {
12497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    //final query result
12507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    info = (CallerInfo) userDataObject;
12517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
12527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (info == null) {
12537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // No URI, or Existing CallerInfo, so we'll have to make do with
12547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // querying a new CallerInfo using the connection's phone number.
12557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    String number = c.getAddress();
12567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
12577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    if (DBG) log("getCallerInfo: number = " + toLogSafePhoneNumber(number));
12587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
12597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    if (!TextUtils.isEmpty(number)) {
12607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        info = CallerInfo.getCallerInfo(context, number);
12617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        if (info != null) {
12627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            c.setUserData(info);
12637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        }
12647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    }
12657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
12667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
12677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
12687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return info;
12697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
12707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
12717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
12727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Class returned by the startGetCallerInfo call to package a temporary
12737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * CallerInfo Object, to be superceded by the CallerInfo Object passed
12747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * into the listener when the query with token mAsyncQueryToken is complete.
12757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
12767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public static class CallerInfoToken {
12777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        /**indicates that there will no longer be updates to this request.*/
12787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        public boolean isFinal;
12797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
12807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        public CallerInfo currentInfo;
12817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        public CallerInfoAsyncQuery asyncQuery;
12827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
12837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
12847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
12857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Start a CallerInfo Query based on the earliest connection in the call.
12867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
12877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static CallerInfoToken startGetCallerInfo(Context context, Call call,
12887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            CallerInfoAsyncQuery.OnQueryCompleteListener listener, Object cookie) {
12897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Connection conn = null;
12907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        int phoneType = call.getPhone().getPhoneType();
12917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
12927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            conn = call.getLatestConnection();
12937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else if ((phoneType == PhoneConstants.PHONE_TYPE_GSM)
1294bd76e4e0407f75c4e6a6961cf943d36fc75a0e1aSailesh Nepal                || (phoneType == PhoneConstants.PHONE_TYPE_SIP)
12950ca1c80f1ca60966a16169b109e96ac19fa69743Etan Cohen                || (phoneType == PhoneConstants.PHONE_TYPE_IMS)
1296bd76e4e0407f75c4e6a6961cf943d36fc75a0e1aSailesh Nepal                || (phoneType == PhoneConstants.PHONE_TYPE_THIRD_PARTY)) {
12977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            conn = call.getEarliestConnection();
12987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
12997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            throw new IllegalStateException("Unexpected phone type: " + phoneType);
13007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
13017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
13027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return startGetCallerInfo(context, conn, listener, cookie);
13037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
13047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1305e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng    static CallerInfoToken startGetCallerInfo(Context context, Connection c,
1306e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng            CallerInfoAsyncQuery.OnQueryCompleteListener listener, Object cookie) {
1307e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng        return startGetCallerInfo(context, c, listener, cookie, null);
1308e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng    }
1309e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng
13107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
13117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * place a temporary callerinfo object in the hands of the caller and notify
13127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * caller when the actual query is done.
13137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
13147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static CallerInfoToken startGetCallerInfo(Context context, Connection c,
1315e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng            CallerInfoAsyncQuery.OnQueryCompleteListener listener, Object cookie,
1316e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng            RawGatewayInfo info) {
13177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        CallerInfoToken cit;
13187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
13197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (c == null) {
13207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            //TODO: perhaps throw an exception here.
13217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            cit = new CallerInfoToken();
13227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            cit.asyncQuery = null;
13237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return cit;
13247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
13257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
13267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Object userDataObject = c.getUserData();
13277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
13287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // There are now 3 states for the Connection's userData object:
13297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //
13307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //   (1) Uri - query has not been executed yet
13317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //
13327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //   (2) CallerInfoToken - query is executing, but has not completed.
13337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //
13347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //   (3) CallerInfo - query has executed.
13357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //
13367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // In each case we have slightly different behaviour:
13377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //   1. If the query has not been executed yet (Uri or null), we start
13387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      query execution asynchronously, and note it by attaching a
13397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      CallerInfoToken as the userData.
13407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //   2. If the query is executing (CallerInfoToken), we've essentially
13417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      reached a state where we've received multiple requests for the
13427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      same callerInfo.  That means that once the query is complete,
13437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      we'll need to execute the additional listener requested.
13447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //   3. If the query has already been executed (CallerInfo), we just
13457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      return the CallerInfo object as expected.
13467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //   4. Regarding isFinal - there are cases where the CallerInfo object
13477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      will not be attached, like when the number is empty (caller id
13487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      blocking).  This flag is used to indicate that the
13497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      CallerInfoToken object is going to be permanent since no
13507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      query results will be returned.  In the case where a query
13517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      has been completed, this flag is used to indicate to the caller
13527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      that the data will not be updated since it is valid.
13537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //
13547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      Note: For the case where a number is NOT retrievable, we leave
13557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      the CallerInfo as null in the CallerInfoToken.  This is
13567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      something of a departure from the original code, since the old
13577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      code manufactured a CallerInfo object regardless of the query
13587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      outcome.  From now on, we will append an empty CallerInfo
13597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      object, to mirror previous behaviour, and to avoid Null Pointer
13607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      Exceptions.
13617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
13627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (userDataObject instanceof Uri) {
13637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // State (1): query has not been executed yet
13647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
13657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            //create a dummy callerinfo, populate with what we know from URI.
13667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            cit = new CallerInfoToken();
13677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            cit.currentInfo = new CallerInfo();
13687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            cit.asyncQuery = CallerInfoAsyncQuery.startQuery(QUERY_TOKEN, context,
13697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    (Uri) userDataObject, sCallerInfoQueryListener, c);
13707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            cit.asyncQuery.addQueryListener(QUERY_TOKEN, listener, cookie);
13717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            cit.isFinal = false;
13727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
13737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            c.setUserData(cit);
13747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
13757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG) log("startGetCallerInfo: query based on Uri: " + userDataObject);
13767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
13777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else if (userDataObject == null) {
13787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // No URI, or Existing CallerInfo, so we'll have to make do with
13797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // querying a new CallerInfo using the connection's phone number.
13807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            String number = c.getAddress();
13817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1382685dcb6b0268af57ac5b93a2e5b259eb519fa2d8Chiao Cheng            if (info != null && info != CallGatewayManager.EMPTY_INFO) {
1383e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng                // Gateway number, the connection number is actually the gateway number.
1384e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng                // need to lookup via dialed number.
1385e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng                number = info.trueNumber;
1386e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng            }
1387e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng
13887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG) {
13897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                log("PhoneUtils.startGetCallerInfo: new query for phone number...");
13907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                log("- number (address): " + toLogSafePhoneNumber(number));
13917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                log("- c: " + c);
13927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                log("- phone: " + c.getCall().getPhone());
13937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                int phoneType = c.getCall().getPhone().getPhoneType();
13947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                log("- phoneType: " + phoneType);
13957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                switch (phoneType) {
13967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    case PhoneConstants.PHONE_TYPE_NONE: log("  ==> PHONE_TYPE_NONE"); break;
13977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    case PhoneConstants.PHONE_TYPE_GSM: log("  ==> PHONE_TYPE_GSM"); break;
13980ca1c80f1ca60966a16169b109e96ac19fa69743Etan Cohen                    case PhoneConstants.PHONE_TYPE_IMS: log("  ==> PHONE_TYPE_IMS"); break;
13997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    case PhoneConstants.PHONE_TYPE_CDMA: log("  ==> PHONE_TYPE_CDMA"); break;
14007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    case PhoneConstants.PHONE_TYPE_SIP: log("  ==> PHONE_TYPE_SIP"); break;
1401bd76e4e0407f75c4e6a6961cf943d36fc75a0e1aSailesh Nepal                    case PhoneConstants.PHONE_TYPE_THIRD_PARTY:
1402bd76e4e0407f75c4e6a6961cf943d36fc75a0e1aSailesh Nepal                        log("  ==> PHONE_TYPE_THIRD_PARTY");
1403bd76e4e0407f75c4e6a6961cf943d36fc75a0e1aSailesh Nepal                        break;
14047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    default: log("  ==> Unknown phone type"); break;
14057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
14067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
14077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
14087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            cit = new CallerInfoToken();
14097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            cit.currentInfo = new CallerInfo();
14107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
14117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // Store CNAP information retrieved from the Connection (we want to do this
14127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // here regardless of whether the number is empty or not).
14137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            cit.currentInfo.cnapName =  c.getCnapName();
14147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            cit.currentInfo.name = cit.currentInfo.cnapName; // This can still get overwritten
14157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                                             // by ContactInfo later
14167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            cit.currentInfo.numberPresentation = c.getNumberPresentation();
14177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            cit.currentInfo.namePresentation = c.getCnapNamePresentation();
14187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
14197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (VDBG) {
14207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                log("startGetCallerInfo: number = " + number);
14217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                log("startGetCallerInfo: CNAP Info from FW(1): name="
14227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    + cit.currentInfo.cnapName
14237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    + ", Name/Number Pres=" + cit.currentInfo.numberPresentation);
14247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
14257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
14267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // handling case where number is null (caller id hidden) as well.
14277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (!TextUtils.isEmpty(number)) {
14287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // Check for special CNAP cases and modify the CallerInfo accordingly
14297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // to be sure we keep the right information to display/log later
14307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                number = modifyForSpecialCnapCases(context, cit.currentInfo, number,
14317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        cit.currentInfo.numberPresentation);
14327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
14337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                cit.currentInfo.phoneNumber = number;
14347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // For scenarios where we may receive a valid number from the network but a
14357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // restricted/unavailable presentation, we do not want to perform a contact query
14367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // (see note on isFinal above). So we set isFinal to true here as well.
14377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (cit.currentInfo.numberPresentation != PhoneConstants.PRESENTATION_ALLOWED) {
14387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    cit.isFinal = true;
14397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                } else {
14407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    if (DBG) log("==> Actually starting CallerInfoAsyncQuery.startQuery()...");
14417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    cit.asyncQuery = CallerInfoAsyncQuery.startQuery(QUERY_TOKEN, context,
14427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            number, sCallerInfoQueryListener, c);
14437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    cit.asyncQuery.addQueryListener(QUERY_TOKEN, listener, cookie);
14447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    cit.isFinal = false;
14457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
14467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            } else {
14477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // This is the case where we are querying on a number that
14487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // is null or empty, like a caller whose caller id is
14497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // blocked or empty (CLIR).  The previous behaviour was to
14507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // throw a null CallerInfo object back to the user, but
14517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // this departure is somewhat cleaner.
14527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (DBG) log("startGetCallerInfo: No query to start, send trivial reply.");
14537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                cit.isFinal = true; // please see note on isFinal, above.
14547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
14557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
14567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            c.setUserData(cit);
14577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
14587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG) {
14597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                log("startGetCallerInfo: query based on number: " + toLogSafePhoneNumber(number));
14607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
14617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
14627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else if (userDataObject instanceof CallerInfoToken) {
14637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // State (2): query is executing, but has not completed.
14647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
14657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // just tack on this listener to the queue.
14667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            cit = (CallerInfoToken) userDataObject;
14677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
14687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // handling case where number is null (caller id hidden) as well.
14697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (cit.asyncQuery != null) {
14707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                cit.asyncQuery.addQueryListener(QUERY_TOKEN, listener, cookie);
14717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
14727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (DBG) log("startGetCallerInfo: query already running, adding listener: " +
14737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        listener.getClass().toString());
14747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            } else {
14757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // handling case where number/name gets updated later on by the network
14767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                String updatedNumber = c.getAddress();
1477e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng
1478e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng                if (info != null) {
1479e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng                    // Gateway number, the connection number is actually the gateway number.
1480e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng                    // need to lookup via dialed number.
1481e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng                    updatedNumber = info.trueNumber;
1482e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng                }
1483e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng
14847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (DBG) {
14857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    log("startGetCallerInfo: updatedNumber initially = "
14867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            + toLogSafePhoneNumber(updatedNumber));
14877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
14887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (!TextUtils.isEmpty(updatedNumber)) {
14897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // Store CNAP information retrieved from the Connection
14907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    cit.currentInfo.cnapName =  c.getCnapName();
14917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // This can still get overwritten by ContactInfo
14927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    cit.currentInfo.name = cit.currentInfo.cnapName;
14937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    cit.currentInfo.numberPresentation = c.getNumberPresentation();
14947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    cit.currentInfo.namePresentation = c.getCnapNamePresentation();
14957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
14967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    updatedNumber = modifyForSpecialCnapCases(context, cit.currentInfo,
14977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            updatedNumber, cit.currentInfo.numberPresentation);
14987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
14997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    cit.currentInfo.phoneNumber = updatedNumber;
15007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    if (DBG) {
15017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        log("startGetCallerInfo: updatedNumber="
15027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                + toLogSafePhoneNumber(updatedNumber));
15037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    }
15047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    if (VDBG) {
15057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        log("startGetCallerInfo: CNAP Info from FW(2): name="
15067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                + cit.currentInfo.cnapName
15077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                + ", Name/Number Pres=" + cit.currentInfo.numberPresentation);
15087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    } else if (DBG) {
15097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        log("startGetCallerInfo: CNAP Info from FW(2)");
15107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    }
15117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // For scenarios where we may receive a valid number from the network but a
15127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // restricted/unavailable presentation, we do not want to perform a contact query
15137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // (see note on isFinal above). So we set isFinal to true here as well.
15147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    if (cit.currentInfo.numberPresentation != PhoneConstants.PRESENTATION_ALLOWED) {
15157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        cit.isFinal = true;
15167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    } else {
15177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        cit.asyncQuery = CallerInfoAsyncQuery.startQuery(QUERY_TOKEN, context,
15187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                updatedNumber, sCallerInfoQueryListener, c);
15197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        cit.asyncQuery.addQueryListener(QUERY_TOKEN, listener, cookie);
15207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        cit.isFinal = false;
15217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    }
15227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                } else {
15237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    if (DBG) log("startGetCallerInfo: No query to attach to, send trivial reply.");
15247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    if (cit.currentInfo == null) {
15257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        cit.currentInfo = new CallerInfo();
15267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    }
15277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // Store CNAP information retrieved from the Connection
15287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    cit.currentInfo.cnapName = c.getCnapName();  // This can still get
15297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                                                 // overwritten by ContactInfo
15307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    cit.currentInfo.name = cit.currentInfo.cnapName;
15317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    cit.currentInfo.numberPresentation = c.getNumberPresentation();
15327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    cit.currentInfo.namePresentation = c.getCnapNamePresentation();
15337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
15347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    if (VDBG) {
15357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        log("startGetCallerInfo: CNAP Info from FW(3): name="
15367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                + cit.currentInfo.cnapName
15377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                + ", Name/Number Pres=" + cit.currentInfo.numberPresentation);
15387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    } else if (DBG) {
15397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        log("startGetCallerInfo: CNAP Info from FW(3)");
15407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    }
15417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    cit.isFinal = true; // please see note on isFinal, above.
15427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
15437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
15447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
15457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // State (3): query is complete.
15467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
15477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // The connection's userDataObject is a full-fledged
15487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // CallerInfo instance.  Wrap it in a CallerInfoToken and
15497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // return it to the user.
15507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
15517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            cit = new CallerInfoToken();
15527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            cit.currentInfo = (CallerInfo) userDataObject;
15537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            cit.asyncQuery = null;
15547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            cit.isFinal = true;
15557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // since the query is already done, call the listener.
15567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG) log("startGetCallerInfo: query already done, returning CallerInfo");
15577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG) log("==> cit.currentInfo = " + cit.currentInfo);
15587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
15597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return cit;
15607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
15617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
15627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
15637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Static CallerInfoAsyncQuery.OnQueryCompleteListener instance that
15647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * we use with all our CallerInfoAsyncQuery.startQuery() requests.
15657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
15667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static final int QUERY_TOKEN = -1;
15677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static CallerInfoAsyncQuery.OnQueryCompleteListener sCallerInfoQueryListener =
15687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        new CallerInfoAsyncQuery.OnQueryCompleteListener () {
15697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            /**
15707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon             * When the query completes, we stash the resulting CallerInfo
15717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon             * object away in the Connection's "userData" (where it will
15727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon             * later be retrieved by the in-call UI.)
15737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon             */
15747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            public void onQueryComplete(int token, Object cookie, CallerInfo ci) {
15757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (DBG) log("query complete, updating connection.userdata");
15767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Connection conn = (Connection) cookie;
15777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
15787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // Added a check if CallerInfo is coming from ContactInfo or from Connection.
15797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // If no ContactInfo, then we want to use CNAP information coming from network
15807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (DBG) log("- onQueryComplete: CallerInfo:" + ci);
15817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (ci.contactExists || ci.isEmergencyNumber() || ci.isVoiceMailNumber()) {
15827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // If the number presentation has not been set by
15837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // the ContactInfo, use the one from the
15847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // connection.
15857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
15867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // TODO: Need a new util method to merge the info
15877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // from the Connection in a CallerInfo object.
15887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // Here 'ci' is a new CallerInfo instance read
15897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // from the DB. It has lost all the connection
15907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // info preset before the query (see PhoneUtils
15917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // line 1334). We should have a method to merge
15927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // back into this new instance the info from the
15937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // connection object not set by the DB. If the
15947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // Connection already has a CallerInfo instance in
15957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // userData, then we could use this instance to
15967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // fill 'ci' in. The same routine could be used in
15977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // PhoneUtils.
15987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    if (0 == ci.numberPresentation) {
15997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        ci.numberPresentation = conn.getNumberPresentation();
16007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    }
16017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                } else {
16027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // No matching contact was found for this number.
16037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // Return a new CallerInfo based solely on the CNAP
16047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // information from the network.
16057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
16067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    CallerInfo newCi = getCallerInfo(null, conn);
16077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
16087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // ...but copy over the (few) things we care about
16097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // from the original CallerInfo object:
16107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    if (newCi != null) {
16117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        newCi.phoneNumber = ci.phoneNumber; // To get formatted phone number
16127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        newCi.geoDescription = ci.geoDescription; // To get geo description string
16137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        ci = newCi;
16147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    }
16157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
16167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
16177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (DBG) log("==> Stashing CallerInfo " + ci + " into the connection...");
16187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                conn.setUserData(ci);
16197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
16207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        };
16217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
16227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
16237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
16247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Returns a single "name" for the specified given a CallerInfo object.
16257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * If the name is null, return defaultString as the default value, usually
16267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * context.getString(R.string.unknown).
16277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
16287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static String getCompactNameFromCallerInfo(CallerInfo ci, Context context) {
16297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("getCompactNameFromCallerInfo: info = " + ci);
16307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
16317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        String compactName = null;
16327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (ci != null) {
16337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (TextUtils.isEmpty(ci.name)) {
16347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // Perform any modifications for special CNAP cases to
16357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // the phone number being displayed, if applicable.
16367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                compactName = modifyForSpecialCnapCases(context, ci, ci.phoneNumber,
16377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                                        ci.numberPresentation);
16387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            } else {
16397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // Don't call modifyForSpecialCnapCases on regular name. See b/2160795.
16407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                compactName = ci.name;
16417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
16427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
16437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
16447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if ((compactName == null) || (TextUtils.isEmpty(compactName))) {
16457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // If we're still null/empty here, then check if we have a presentation
16467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // string that takes precedence that we could return, otherwise display
16477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // "unknown" string.
16487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (ci != null && ci.numberPresentation == PhoneConstants.PRESENTATION_RESTRICTED) {
16497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                compactName = context.getString(R.string.private_num);
16507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            } else if (ci != null && ci.numberPresentation == PhoneConstants.PRESENTATION_PAYPHONE) {
16517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                compactName = context.getString(R.string.payphone);
16527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            } else {
16537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                compactName = context.getString(R.string.unknown);
16547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
16557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
16567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (VDBG) log("getCompactNameFromCallerInfo: compactName=" + compactName);
16577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return compactName;
16587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
16597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
16607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
16617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Returns true if the specified Call is a "conference call", meaning
16627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * that it owns more than one Connection object.  This information is
16637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * used to trigger certain UI changes that appear when a conference
16647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * call is active (like displaying the label "Conference call", and
16657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * enabling the "Manage conference" UI.)
16667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
16677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Watch out: This method simply checks the number of Connections,
16687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * *not* their states.  So if a Call has (for example) one ACTIVE
16697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * connection and one DISCONNECTED connection, this method will return
16707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * true (which is unintuitive, since the Call isn't *really* a
16717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * conference call any more.)
16727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
16737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return true if the specified call has more than one connection (in any state.)
16747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
16757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static boolean isConferenceCall(Call call) {
16767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // CDMA phones don't have the same concept of "conference call" as
16777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // GSM phones do; there's no special "conference call" state of
16787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // the UI or a "manage conference" function.  (Instead, when
16797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // you're in a 3-way call, all we can do is display the "generic"
16807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // state of the UI.)  So as far as the in-call UI is concerned,
16817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Conference corresponds to generic display.
16827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final PhoneGlobals app = PhoneGlobals.getInstance();
16837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        int phoneType = call.getPhone().getPhoneType();
16847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
16857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            CdmaPhoneCallState.PhoneCallState state = app.cdmaPhoneCallState.getCurrentCallState();
16867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if ((state == CdmaPhoneCallState.PhoneCallState.CONF_CALL)
16877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    || ((state == CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE)
16887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    && !app.cdmaPhoneCallState.IsThreeWayCallOrigStateDialing())) {
16897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                return true;
16907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
16917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
16927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            List<Connection> connections = call.getConnections();
16937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (connections != null && connections.size() > 1) {
16947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                return true;
16957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
16967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
16977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return false;
16987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
16997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // TODO: We may still want to change the semantics of this method
17007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // to say that a given call is only really a conference call if
17017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // the number of ACTIVE connections, not the total number of
17027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // connections, is greater than one.  (See warning comment in the
17037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // javadoc above.)
17047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Here's an implementation of that:
17057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //        if (connections == null) {
17067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //            return false;
17077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //        }
17087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //        int numActiveConnections = 0;
17097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //        for (Connection conn : connections) {
17107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //            if (DBG) log("  - CONN: " + conn + ", state = " + conn.getState());
17117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //            if (conn.getState() == Call.State.ACTIVE) numActiveConnections++;
17127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //            if (numActiveConnections > 1) {
17137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //                return true;
17147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //            }
17157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //        }
17167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //        return false;
17177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
17187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
17197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
17207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Launch the Dialer to start a new call.
17217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * This is just a wrapper around the ACTION_DIAL intent.
17227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
17237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /* package */ static boolean startNewCall(final CallManager cm) {
17247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final PhoneGlobals app = PhoneGlobals.getInstance();
17257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
17267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Sanity-check that this is OK given the current state of the phone.
17277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (!okToAddCall(cm)) {
17287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Log.w(LOG_TAG, "startNewCall: can't add a new call in the current state");
17297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            dumpCallManager();
17307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return false;
17317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
17327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
17337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Intent intent = new Intent(Intent.ACTION_DIAL);
17347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
17357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
17367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // when we request the dialer come up, we also want to inform
17377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // it that we're going through the "add call" option from the
17387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // InCallScreen / PhoneUtils.
17397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        intent.putExtra(ADD_CALL_MODE_KEY, true);
17407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        try {
17417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            app.startActivity(intent);
17427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } catch (ActivityNotFoundException e) {
17437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // This is rather rare but possible.
17447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // Note: this method is used even when the phone is encrypted. At that moment
17457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // the system may not find any Activity which can accept this Intent.
17467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Log.e(LOG_TAG, "Activity for adding calls isn't found.");
17477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return false;
17487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
17497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
17507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return true;
17517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
17527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
17537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
17547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Turns on/off speaker.
17557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
17567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param context Context
17577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param flag True when speaker should be on. False otherwise.
17587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param store True when the settings should be stored in the device.
17597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
17607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /* package */ static void turnOnSpeaker(Context context, boolean flag, boolean store) {
17617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("turnOnSpeaker(flag=" + flag + ", store=" + store + ")...");
17627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final PhoneGlobals app = PhoneGlobals.getInstance();
17637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
17647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
17657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        audioManager.setSpeakerphoneOn(flag);
17667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
17677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // record the speaker-enable value
17687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (store) {
17697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            sIsSpeakerEnabled = flag;
17707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
17717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
17727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // We also need to make a fresh call to PhoneApp.updateWakeState()
17737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // any time the speaker state changes, since the screen timeout is
17747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // sometimes different depending on whether or not the speaker is
17757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // in use.
17767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        app.updateWakeState();
17777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1778eee6a9e11d50f918b278dad2133cc6408e27369dHariprasad Jayakumar        app.mCM.setEchoSuppressionEnabled();
17797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
17807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
17817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
17827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Restore the speaker mode, called after a wired headset disconnect
17837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * event.
17847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
17857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static void restoreSpeakerMode(Context context) {
17867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("restoreSpeakerMode, restoring to: " + sIsSpeakerEnabled);
17877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
17887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // change the mode if needed.
17897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (isSpeakerOn(context) != sIsSpeakerEnabled) {
17907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            turnOnSpeaker(context, sIsSpeakerEnabled, false);
17917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
17927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
17937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
17947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static boolean isSpeakerOn(Context context) {
17957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
17967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return audioManager.isSpeakerphoneOn();
17977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
17987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
17997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
18007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static void turnOnNoiseSuppression(Context context, boolean flag, boolean store) {
18017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("turnOnNoiseSuppression: " + flag);
18027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
18037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
18043b9c21fad915066c537fde5a8bf83fdc65891085Jonathan Basseri        PersistableBundle b = PhoneGlobals.getInstance().getCarrierConfig();
18053b9c21fad915066c537fde5a8bf83fdc65891085Jonathan Basseri        if (!b.getBoolean(CarrierConfigManager.KEY_HAS_IN_CALL_NOISE_SUPPRESSION_BOOL)) {
18067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return;
18077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
18087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
18097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (flag) {
18107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            audioManager.setParameters("noise_suppression=auto");
18117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
18127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            audioManager.setParameters("noise_suppression=off");
18137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
18147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
18157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // record the speaker-enable value
18167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (store) {
18177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            sIsNoiseSuppressionEnabled = flag;
18187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
18197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
18207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // TODO: implement and manage ICON
18217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
18227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
18237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
18247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static void restoreNoiseSuppression(Context context) {
18257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("restoreNoiseSuppression, restoring to: " + sIsNoiseSuppressionEnabled);
18267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
18273b9c21fad915066c537fde5a8bf83fdc65891085Jonathan Basseri        PersistableBundle b = PhoneGlobals.getInstance().getCarrierConfig();
18283b9c21fad915066c537fde5a8bf83fdc65891085Jonathan Basseri        if (!b.getBoolean(CarrierConfigManager.KEY_HAS_IN_CALL_NOISE_SUPPRESSION_BOOL)) {
18297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return;
18307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
18317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
18327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // change the mode if needed.
18337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (isNoiseSuppressionOn(context) != sIsNoiseSuppressionEnabled) {
18347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            turnOnNoiseSuppression(context, sIsNoiseSuppressionEnabled, false);
18357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
18367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
18377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
18387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static boolean isNoiseSuppressionOn(Context context) {
18397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
18403b9c21fad915066c537fde5a8bf83fdc65891085Jonathan Basseri        PersistableBundle b = PhoneGlobals.getInstance().getCarrierConfig();
18413b9c21fad915066c537fde5a8bf83fdc65891085Jonathan Basseri        if (!b.getBoolean(CarrierConfigManager.KEY_HAS_IN_CALL_NOISE_SUPPRESSION_BOOL)) {
18427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return false;
18437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
18447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
18457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
18467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        String noiseSuppression = audioManager.getParameters("noise_suppression");
18477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("isNoiseSuppressionOn: " + noiseSuppression);
18487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (noiseSuppression.contains("off")) {
18497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return false;
18507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
18517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return true;
18527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
18537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
18547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1855c264cba0b6ea81b3f741d9c41a0a50b7ffd19220Santos Cordon    static boolean isInEmergencyCall(CallManager cm) {
1856baeabcf139c95c1b9c4446d3b46497837dee9744Brad Ebinger        Call fgCall = cm.getActiveFgCall();
1857baeabcf139c95c1b9c4446d3b46497837dee9744Brad Ebinger        // isIdle includes checks for the DISCONNECTING/DISCONNECTED state.
1858baeabcf139c95c1b9c4446d3b46497837dee9744Brad Ebinger        if(!fgCall.isIdle()) {
1859baeabcf139c95c1b9c4446d3b46497837dee9744Brad Ebinger            for (Connection cn : fgCall.getConnections()) {
1860baeabcf139c95c1b9c4446d3b46497837dee9744Brad Ebinger                if (PhoneNumberUtils.isLocalEmergencyNumber(PhoneGlobals.getInstance(),
1861baeabcf139c95c1b9c4446d3b46497837dee9744Brad Ebinger                        cn.getAddress())) {
1862baeabcf139c95c1b9c4446d3b46497837dee9744Brad Ebinger                    return true;
1863baeabcf139c95c1b9c4446d3b46497837dee9744Brad Ebinger                }
1864c264cba0b6ea81b3f741d9c41a0a50b7ffd19220Santos Cordon            }
1865c264cba0b6ea81b3f741d9c41a0a50b7ffd19220Santos Cordon        }
1866c264cba0b6ea81b3f741d9c41a0a50b7ffd19220Santos Cordon        return false;
1867c264cba0b6ea81b3f741d9c41a0a50b7ffd19220Santos Cordon    }
1868c264cba0b6ea81b3f741d9c41a0a50b7ffd19220Santos Cordon
18697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
18707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Get the mute state of foreground phone, which has the current
18717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * foreground call
18727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
18737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static boolean getMute() {
1874bb2bcef62b916b1b544195ca671d56af6ed32cc2Santos Cordon        return false;
18757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
18767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
18777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /* package */ static void setAudioMode() {
18787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
18797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
18807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
18817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Sets the audio mode per current phone state.
18827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
18837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /* package */ static void setAudioMode(CallManager cm) {
18847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
18857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
18867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
18877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Look for ANY connections on the phone that qualify as being
18887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * disconnected.
18897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
18907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return true if we find a connection that is disconnected over
18917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * all the phone's call objects.
18927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
18937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /* package */ static boolean hasDisconnectedConnections(Phone phone) {
18947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return hasDisconnectedConnections(phone.getForegroundCall()) ||
18957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                hasDisconnectedConnections(phone.getBackgroundCall()) ||
18967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                hasDisconnectedConnections(phone.getRingingCall());
18977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
18987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
18997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
19007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Iterate over all connections in a call to see if there are any
19017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * that are not alive (disconnected or idle).
19027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
19037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return true if we find a connection that is disconnected, and
19047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * pending removal via
19056d83e5eb90ee8b4551d61c4789bb8f124c4c12d2Amit Mahajan     * {@link com.android.internal.telephony.Call#clearDisconnected()}.
19067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
19077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static final boolean hasDisconnectedConnections(Call call) {
19087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // look through all connections for non-active ones.
19097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        for (Connection c : call.getConnections()) {
19107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (!c.isAlive()) {
19117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                return true;
19127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
19137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
19147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return false;
19157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
19167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
19177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    //
19187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    // Misc UI policy helper functions
19197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    //
19207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
19217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
1922af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen     * @return true if we're allowed to hold calls, given the current
1923af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen     * state of the Phone.
1924af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen     */
1925af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen    /* package */ static boolean okToHoldCall(CallManager cm) {
1926af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen        final Call fgCall = cm.getActiveFgCall();
1927af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen        final boolean hasHoldingCall = cm.hasActiveBgCall();
1928af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen        final Call.State fgCallState = fgCall.getState();
1929af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen
1930af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen        // The "Hold" control is disabled entirely if there's
1931af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen        // no way to either hold or unhold in the current state.
1932af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen        final boolean okToHold = (fgCallState == Call.State.ACTIVE) && !hasHoldingCall;
1933af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen        final boolean okToUnhold = cm.hasActiveBgCall() && (fgCallState == Call.State.IDLE);
1934af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen        final boolean canHold = okToHold || okToUnhold;
1935af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen
1936af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen        return canHold;
1937af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen    }
1938af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen
1939af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen    /**
1940af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen     * @return true if we support holding calls, given the current
1941af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen     * state of the Phone.
1942af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen     */
1943af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen    /* package */ static boolean okToSupportHold(CallManager cm) {
1944af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen        boolean supportsHold = false;
1945af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen
1946af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen        final Call fgCall = cm.getActiveFgCall();
1947af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen        final boolean hasHoldingCall = cm.hasActiveBgCall();
1948af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen        final Call.State fgCallState = fgCall.getState();
1949af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen
1950af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen        if (TelephonyCapabilities.supportsHoldAndUnhold(fgCall.getPhone())) {
1951af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen            // This phone has the concept of explicit "Hold" and "Unhold" actions.
1952af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen            supportsHold = true;
1953af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen        } else if (hasHoldingCall && (fgCallState == Call.State.IDLE)) {
1954af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen            // Even when foreground phone device doesn't support hold/unhold, phone devices
1955af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen            // for background holding calls may do.
1956af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen            final Call bgCall = cm.getFirstActiveBgCall();
1957af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen            if (bgCall != null &&
1958af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen                    TelephonyCapabilities.supportsHoldAndUnhold(bgCall.getPhone())) {
1959af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen                supportsHold = true;
1960af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen            }
1961af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen        }
1962af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen        return supportsHold;
1963af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen    }
1964af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen
1965af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen    /**
19667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return true if we're allowed to swap calls, given the current
19677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * state of the Phone.
19687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
19697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /* package */ static boolean okToSwapCalls(CallManager cm) {
19707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        int phoneType = cm.getDefaultPhone().getPhoneType();
19717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
19727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // CDMA: "Swap" is enabled only when the phone reaches a *generic*.
19737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // state by either accepting a Call Waiting or by merging two calls
19747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            PhoneGlobals app = PhoneGlobals.getInstance();
19757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return (app.cdmaPhoneCallState.getCurrentCallState()
19767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    == CdmaPhoneCallState.PhoneCallState.CONF_CALL);
19777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else if ((phoneType == PhoneConstants.PHONE_TYPE_GSM)
1978bd76e4e0407f75c4e6a6961cf943d36fc75a0e1aSailesh Nepal                || (phoneType == PhoneConstants.PHONE_TYPE_SIP)
19790ca1c80f1ca60966a16169b109e96ac19fa69743Etan Cohen                || (phoneType == PhoneConstants.PHONE_TYPE_IMS)
1980bd76e4e0407f75c4e6a6961cf943d36fc75a0e1aSailesh Nepal                || (phoneType == PhoneConstants.PHONE_TYPE_THIRD_PARTY)) {
19817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // GSM: "Swap" is available if both lines are in use and there's no
19827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // incoming call.  (Actually we need to verify that the active
19837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // call really is in the ACTIVE state and the holding call really
19847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // is in the HOLDING state, since you *can't* actually swap calls
19857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // when the foreground call is DIALING or ALERTING.)
19867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return !cm.hasActiveRingingCall()
19877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    && (cm.getActiveFgCall().getState() == Call.State.ACTIVE)
19887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    && (cm.getFirstActiveBgCall().getState() == Call.State.HOLDING);
19897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
19907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            throw new IllegalStateException("Unexpected phone type: " + phoneType);
19917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
19927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
19937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
19947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
19957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return true if we're allowed to merge calls, given the current
19967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * state of the Phone.
19977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
19987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /* package */ static boolean okToMergeCalls(CallManager cm) {
19997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        int phoneType = cm.getFgPhone().getPhoneType();
20007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
20017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // CDMA: "Merge" is enabled only when the user is in a 3Way call.
20027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            PhoneGlobals app = PhoneGlobals.getInstance();
20037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return ((app.cdmaPhoneCallState.getCurrentCallState()
20047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    == CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE)
20057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    && !app.cdmaPhoneCallState.IsThreeWayCallOrigStateDialing());
20067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
20077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // GSM: "Merge" is available if both lines are in use and there's no
20087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // incoming call, *and* the current conference isn't already
20097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // "full".
20107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // TODO: shall move all okToMerge logic to CallManager
20117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return !cm.hasActiveRingingCall() && cm.hasActiveFgCall()
20127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    && cm.hasActiveBgCall()
20137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    && cm.canConference(cm.getFirstActiveBgCall());
20147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
20157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
20167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
20177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
20187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return true if the UI should let you add a new call, given the current
20197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * state of the Phone.
20207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
20217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /* package */ static boolean okToAddCall(CallManager cm) {
20227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Phone phone = cm.getActiveFgCall().getPhone();
20237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
20247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // "Add call" is never allowed in emergency callback mode (ECM).
20257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (isPhoneInEcm(phone)) {
20267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return false;
20277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
20287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
20297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        int phoneType = phone.getPhoneType();
20307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final Call.State fgCallState = cm.getActiveFgCall().getState();
20317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
20327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon           // CDMA: "Add call" button is only enabled when:
20337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon           // - ForegroundCall is in ACTIVE state
20347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon           // - After 30 seconds of user Ignoring/Missing a Call Waiting call.
20357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            PhoneGlobals app = PhoneGlobals.getInstance();
20367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return ((fgCallState == Call.State.ACTIVE)
20377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    && (app.cdmaPhoneCallState.getAddCallMenuStateAfterCallWaiting()));
20387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else if ((phoneType == PhoneConstants.PHONE_TYPE_GSM)
2039bd76e4e0407f75c4e6a6961cf943d36fc75a0e1aSailesh Nepal                || (phoneType == PhoneConstants.PHONE_TYPE_SIP)
20400ca1c80f1ca60966a16169b109e96ac19fa69743Etan Cohen                || (phoneType == PhoneConstants.PHONE_TYPE_IMS)
2041bd76e4e0407f75c4e6a6961cf943d36fc75a0e1aSailesh Nepal                || (phoneType == PhoneConstants.PHONE_TYPE_THIRD_PARTY)) {
20427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // GSM: "Add call" is available only if ALL of the following are true:
20437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // - There's no incoming ringing call
20447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // - There's < 2 lines in use
20457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // - The foreground call is ACTIVE or IDLE or DISCONNECTED.
20467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            //   (We mainly need to make sure it *isn't* DIALING or ALERTING.)
20477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            final boolean hasRingingCall = cm.hasActiveRingingCall();
20487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            final boolean hasActiveCall = cm.hasActiveFgCall();
20497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            final boolean hasHoldingCall = cm.hasActiveBgCall();
20507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            final boolean allLinesTaken = hasActiveCall && hasHoldingCall;
20517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
20527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return !hasRingingCall
20537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    && !allLinesTaken
20547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    && ((fgCallState == Call.State.ACTIVE)
20557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        || (fgCallState == Call.State.IDLE)
20567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        || (fgCallState == Call.State.DISCONNECTED));
20577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
20587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            throw new IllegalStateException("Unexpected phone type: " + phoneType);
20597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
20607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
20617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
20627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
20637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Based on the input CNAP number string,
20647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return _RESTRICTED or _UNKNOWN for all the special CNAP strings.
20657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Otherwise, return CNAP_SPECIAL_CASE_NO.
20667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
20677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static int checkCnapSpecialCases(String n) {
20687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (n.equals("PRIVATE") ||
20697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                n.equals("P") ||
20707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                n.equals("RES")) {
20717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG) log("checkCnapSpecialCases, PRIVATE string: " + n);
20727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return PhoneConstants.PRESENTATION_RESTRICTED;
20737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else if (n.equals("UNAVAILABLE") ||
20747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                n.equals("UNKNOWN") ||
20757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                n.equals("UNA") ||
20767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                n.equals("U")) {
20777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG) log("checkCnapSpecialCases, UNKNOWN string: " + n);
20787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return PhoneConstants.PRESENTATION_UNKNOWN;
20797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
20807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG) log("checkCnapSpecialCases, normal str. number: " + n);
20817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return CNAP_SPECIAL_CASE_NO;
20827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
20837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
20847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
20857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
20867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Handles certain "corner cases" for CNAP. When we receive weird phone numbers
20877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * from the network to indicate different number presentations, convert them to
20887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * expected number and presentation values within the CallerInfo object.
20897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param number number we use to verify if we are in a corner case
20907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param presentation presentation value used to verify if we are in a corner case
20917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return the new String that should be used for the phone number
20927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
20937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /* package */ static String modifyForSpecialCnapCases(Context context, CallerInfo ci,
20947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            String number, int presentation) {
20957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Obviously we return number if ci == null, but still return number if
20967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // number == null, because in these cases the correct string will still be
20977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // displayed/logged after this function returns based on the presentation value.
20987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (ci == null || number == null) return number;
20997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
21007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) {
21017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            log("modifyForSpecialCnapCases: initially, number="
21027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    + toLogSafePhoneNumber(number)
21037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    + ", presentation=" + presentation + " ci " + ci);
21047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
21057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
21067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // "ABSENT NUMBER" is a possible value we could get from the network as the
21077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // phone number, so if this happens, change it to "Unknown" in the CallerInfo
21087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // and fix the presentation to be the same.
21097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final String[] absentNumberValues =
21107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                context.getResources().getStringArray(R.array.absent_num);
21117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (Arrays.asList(absentNumberValues).contains(number)
21127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                && presentation == PhoneConstants.PRESENTATION_ALLOWED) {
21137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            number = context.getString(R.string.unknown);
21147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            ci.numberPresentation = PhoneConstants.PRESENTATION_UNKNOWN;
21157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
21167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
21177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Check for other special "corner cases" for CNAP and fix them similarly. Corner
21187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // cases only apply if we received an allowed presentation from the network, so check
21197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // if we think we have an allowed presentation, or if the CallerInfo presentation doesn't
21207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // match the presentation passed in for verification (meaning we changed it previously
21217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // because it's a corner case and we're being called from a different entry point).
21227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (ci.numberPresentation == PhoneConstants.PRESENTATION_ALLOWED
21237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                || (ci.numberPresentation != presentation
21247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        && presentation == PhoneConstants.PRESENTATION_ALLOWED)) {
21257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            int cnapSpecialCase = checkCnapSpecialCases(number);
21267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (cnapSpecialCase != CNAP_SPECIAL_CASE_NO) {
21277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // For all special strings, change number & numberPresentation.
21287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (cnapSpecialCase == PhoneConstants.PRESENTATION_RESTRICTED) {
21297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    number = context.getString(R.string.private_num);
21307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                } else if (cnapSpecialCase == PhoneConstants.PRESENTATION_UNKNOWN) {
21317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    number = context.getString(R.string.unknown);
21327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
21337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (DBG) {
21347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    log("SpecialCnap: number=" + toLogSafePhoneNumber(number)
21357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            + "; presentation now=" + cnapSpecialCase);
21367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
21377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                ci.numberPresentation = cnapSpecialCase;
21387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
21397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
21407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) {
21417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            log("modifyForSpecialCnapCases: returning number string="
21427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    + toLogSafePhoneNumber(number));
21437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
21447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return number;
21457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
21467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
21477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    //
21487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    // Support for 3rd party phone service providers.
21497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    //
21507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
21517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
21527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Check if a phone number can be route through a 3rd party
21537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * gateway. The number must be a global phone number in numerical
21547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * form (1-800-666-SEXY won't work).
21557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
21567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * MMI codes and the like cannot be used as a dial number for the
21577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * gateway either.
21587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
21597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param number To be dialed via a 3rd party gateway.
21607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return true If the number can be routed through the 3rd party network.
21617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
216269a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon    private static boolean isRoutableViaGateway(String number) {
21637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (TextUtils.isEmpty(number)) {
21647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return false;
21657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
21667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        number = PhoneNumberUtils.stripSeparators(number);
21677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (!number.equals(PhoneNumberUtils.convertKeypadLettersToDigits(number))) {
21687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return false;
21697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
21707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        number = PhoneNumberUtils.extractNetworkPortion(number);
21717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return PhoneNumberUtils.isGlobalPhoneNumber(number);
21727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
21737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
21747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
21757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Returns whether the phone is in ECM ("Emergency Callback Mode") or not.
21767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
21777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /* package */ static boolean isPhoneInEcm(Phone phone) {
21787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if ((phone != null) && TelephonyCapabilities.supportsEcm(phone)) {
2179dd21031e41b68706b01efc79fefcf8e6a1bf944aShuo Qian            return phone.isInEcm();
21807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
21817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return false;
21827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
21837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
21847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
21857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Returns the most appropriate Phone object to handle a call
21867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * to the specified number.
21877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
21887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param cm the CallManager.
21897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param scheme the scheme from the data URI that the number originally came from.
21907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param number the phone number, or SIP address.
21917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
2192bfb6832c4bcc535aef12b07ac5bcf4a973c65d00Sailesh Nepal    public static Phone pickPhoneBasedOnNumber(CallManager cm, String scheme, String number,
2193bfb6832c4bcc535aef12b07ac5bcf4a973c65d00Sailesh Nepal            String primarySipUri, ComponentName thirdPartyCallComponent) {
21947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) {
21957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            log("pickPhoneBasedOnNumber: scheme " + scheme
21967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    + ", number " + toLogSafePhoneNumber(number)
21977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    + ", sipUri "
2198bfb6832c4bcc535aef12b07ac5bcf4a973c65d00Sailesh Nepal                    + (primarySipUri != null ? Uri.parse(primarySipUri).toSafeString() : "null")
2199bfb6832c4bcc535aef12b07ac5bcf4a973c65d00Sailesh Nepal                    + ", thirdPartyCallComponent: " + thirdPartyCallComponent);
22007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
22017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
22027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (primarySipUri != null) {
22037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Phone phone = getSipPhoneFromUri(cm, primarySipUri);
22047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (phone != null) return phone;
22057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
2206bfb6832c4bcc535aef12b07ac5bcf4a973c65d00Sailesh Nepal
22077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return cm.getDefaultPhone();
22087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
22097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
22107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public static Phone getSipPhoneFromUri(CallManager cm, String target) {
22117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        for (Phone phone : cm.getAllPhones()) {
22127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_SIP) {
22137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                String sipUri = ((SipPhone) phone).getSipUri();
22147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (target.equals(sipUri)) {
22157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    if (DBG) log("- pickPhoneBasedOnNumber:" +
22167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            "found SipPhone! obj = " + phone + ", "
22177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            + phone.getClass());
22187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    return phone;
22197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
22207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
22217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
22227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return null;
22237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
22247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
22257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
22267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Returns true when the given call is in INCOMING state and there's no foreground phone call,
22277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * meaning the call is the first real incoming call the phone is having.
22287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
22297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public static boolean isRealIncomingCall(Call.State state) {
22307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return (state == Call.State.INCOMING && !PhoneGlobals.getInstance().mCM.hasActiveFgCall());
22317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
22327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
22337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public static String getPresentationString(Context context, int presentation) {
22347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        String name = context.getString(R.string.unknown);
22357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (presentation == PhoneConstants.PRESENTATION_RESTRICTED) {
22367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            name = context.getString(R.string.private_num);
22377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else if (presentation == PhoneConstants.PRESENTATION_PAYPHONE) {
22387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            name = context.getString(R.string.payphone);
22397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
22407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return name;
22417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
22427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
22437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public static void sendViewNotificationAsync(Context context, Uri contactUri) {
22447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) Log.d(LOG_TAG, "Send view notification to Contacts (uri: " + contactUri + ")");
22457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Intent intent = new Intent("com.android.contacts.VIEW_NOTIFICATION", contactUri);
22467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        intent.setClassName("com.android.contacts",
22477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                "com.android.contacts.ViewNotificationService");
22487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        context.startService(intent);
22497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
22507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
22517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    //
22527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    // General phone and call state debugging/testing code
22537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    //
22547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
22557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /* package */ static void dumpCallState(Phone phone) {
22567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        PhoneGlobals app = PhoneGlobals.getInstance();
22577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Log.d(LOG_TAG, "dumpCallState():");
22587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Log.d(LOG_TAG, "- Phone: " + phone + ", name = " + phone.getPhoneName()
22597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon              + ", state = " + phone.getState());
22607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
22617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        StringBuilder b = new StringBuilder(128);
22627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
22637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Call call = phone.getForegroundCall();
22647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.setLength(0);
22657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append("  - FG call: ").append(call.getState());
22667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" isAlive ").append(call.getState().isAlive());
22677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" isRinging ").append(call.getState().isRinging());
22687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" isDialing ").append(call.getState().isDialing());
22697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" isIdle ").append(call.isIdle());
22707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" hasConnections ").append(call.hasConnections());
22717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Log.d(LOG_TAG, b.toString());
22727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
22737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        call = phone.getBackgroundCall();
22747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.setLength(0);
22757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append("  - BG call: ").append(call.getState());
22767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" isAlive ").append(call.getState().isAlive());
22777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" isRinging ").append(call.getState().isRinging());
22787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" isDialing ").append(call.getState().isDialing());
22797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" isIdle ").append(call.isIdle());
22807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" hasConnections ").append(call.hasConnections());
22817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Log.d(LOG_TAG, b.toString());
22827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
22837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        call = phone.getRingingCall();
22847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.setLength(0);
22857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append("  - RINGING call: ").append(call.getState());
22867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" isAlive ").append(call.getState().isAlive());
22877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" isRinging ").append(call.getState().isRinging());
22887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" isDialing ").append(call.getState().isDialing());
22897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" isIdle ").append(call.isIdle());
22907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" hasConnections ").append(call.hasConnections());
22917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Log.d(LOG_TAG, b.toString());
22927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
22937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
22947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final boolean hasRingingCall = !phone.getRingingCall().isIdle();
22957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final boolean hasActiveCall = !phone.getForegroundCall().isIdle();
22967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final boolean hasHoldingCall = !phone.getBackgroundCall().isIdle();
22977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final boolean allLinesTaken = hasActiveCall && hasHoldingCall;
22987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.setLength(0);
22997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append("  - hasRingingCall ").append(hasRingingCall);
23007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" hasActiveCall ").append(hasActiveCall);
23017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" hasHoldingCall ").append(hasHoldingCall);
23027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" allLinesTaken ").append(allLinesTaken);
23037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Log.d(LOG_TAG, b.toString());
23047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
23057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // On CDMA phones, dump out the CdmaPhoneCallState too:
23067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {
23077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (app.cdmaPhoneCallState != null) {
23087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Log.d(LOG_TAG, "  - CDMA call state: "
23097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                      + app.cdmaPhoneCallState.getCurrentCallState());
23107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            } else {
23117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Log.d(LOG_TAG, "  - CDMA device, but null cdmaPhoneCallState!");
23127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
23137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
23147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
23157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
23167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static void log(String msg) {
23177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Log.d(LOG_TAG, msg);
23187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
23197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
23207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static void dumpCallManager() {
23217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Call call;
23227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        CallManager cm = PhoneGlobals.getInstance().mCM;
23237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        StringBuilder b = new StringBuilder(128);
23247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
23257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
23267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
23277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Log.d(LOG_TAG, "############### dumpCallManager() ##############");
23287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // TODO: Don't log "cm" itself, since CallManager.toString()
23297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // already spews out almost all this same information.
23307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // We should fix CallManager.toString() to be more minimal, and
23317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // use an explicit dumpState() method for the verbose dump.
23327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Log.d(LOG_TAG, "CallManager: " + cm
23337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //         + ", state = " + cm.getState());
23347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Log.d(LOG_TAG, "CallManager: state = " + cm.getState());
23357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.setLength(0);
23367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        call = cm.getActiveFgCall();
23377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" - FG call: ").append(cm.hasActiveFgCall()? "YES ": "NO ");
23387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(call);
23397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append( "  State: ").append(cm.getActiveFgCallState());
23407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append( "  Conn: ").append(cm.getFgCallConnections());
23417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Log.d(LOG_TAG, b.toString());
23427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.setLength(0);
23437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        call = cm.getFirstActiveBgCall();
23447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" - BG call: ").append(cm.hasActiveBgCall()? "YES ": "NO ");
23457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(call);
23467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append( "  State: ").append(cm.getFirstActiveBgCall().getState());
23477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append( "  Conn: ").append(cm.getBgCallConnections());
23487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Log.d(LOG_TAG, b.toString());
23497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.setLength(0);
23507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        call = cm.getFirstActiveRingingCall();
23517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" - RINGING call: ").append(cm.hasActiveRingingCall()? "YES ": "NO ");
23527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(call);
23537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append( "  State: ").append(cm.getFirstActiveRingingCall().getState());
23547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Log.d(LOG_TAG, b.toString());
23557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
23567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
23577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
23587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        for (Phone phone : CallManager.getInstance().getAllPhones()) {
23597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (phone != null) {
23607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Log.d(LOG_TAG, "Phone: " + phone + ", name = " + phone.getPhoneName()
23617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        + ", state = " + phone.getState());
23627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                b.setLength(0);
23637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                call = phone.getForegroundCall();
23647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                b.append(" - FG call: ").append(call);
23657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                b.append( "  State: ").append(call.getState());
23667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                b.append( "  Conn: ").append(call.hasConnections());
23677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Log.d(LOG_TAG, b.toString());
23687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                b.setLength(0);
23697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                call = phone.getBackgroundCall();
23707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                b.append(" - BG call: ").append(call);
23717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                b.append( "  State: ").append(call.getState());
23727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                b.append( "  Conn: ").append(call.hasConnections());
23737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Log.d(LOG_TAG, b.toString());b.setLength(0);
23747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                call = phone.getRingingCall();
23757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                b.append(" - RINGING call: ").append(call);
23767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                b.append( "  State: ").append(call.getState());
23777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                b.append( "  Conn: ").append(call.hasConnections());
23787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Log.d(LOG_TAG, b.toString());
23797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
23807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
23817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
23827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Log.d(LOG_TAG, "############## END dumpCallManager() ###############");
23837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
23847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
23857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
23867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return if the context is in landscape orientation.
23877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
23887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public static boolean isLandscape(Context context) {
23897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return context.getResources().getConfiguration().orientation
23907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                == Configuration.ORIENTATION_LANDSCAPE;
23917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
2392d5165b05c851ecd47d330b600ed2768e0db8b9d1Andrew Lee
2393e53a064be1bcea3ec2acb3c7681fa9a2762f4e3eNancy Chen    public static PhoneAccountHandle makePstnPhoneAccountHandle(String id) {
2394e53a064be1bcea3ec2acb3c7681fa9a2762f4e3eNancy Chen        return makePstnPhoneAccountHandleWithPrefix(id, "", false);
2395e53a064be1bcea3ec2acb3c7681fa9a2762f4e3eNancy Chen    }
2396e53a064be1bcea3ec2acb3c7681fa9a2762f4e3eNancy Chen
239732031f403cadffdcb27375d8ffee3482d19953abNancy Chen    public static PhoneAccountHandle makePstnPhoneAccountHandle(int phoneId) {
239832031f403cadffdcb27375d8ffee3482d19953abNancy Chen        return makePstnPhoneAccountHandle(PhoneFactory.getPhone(phoneId));
239932031f403cadffdcb27375d8ffee3482d19953abNancy Chen    }
240032031f403cadffdcb27375d8ffee3482d19953abNancy Chen
2401d5165b05c851ecd47d330b600ed2768e0db8b9d1Andrew Lee    public static PhoneAccountHandle makePstnPhoneAccountHandle(Phone phone) {
2402d5165b05c851ecd47d330b600ed2768e0db8b9d1Andrew Lee        return makePstnPhoneAccountHandleWithPrefix(phone, "", false);
2403d5165b05c851ecd47d330b600ed2768e0db8b9d1Andrew Lee    }
2404d5165b05c851ecd47d330b600ed2768e0db8b9d1Andrew Lee
2405d5165b05c851ecd47d330b600ed2768e0db8b9d1Andrew Lee    public static PhoneAccountHandle makePstnPhoneAccountHandleWithPrefix(
2406d5165b05c851ecd47d330b600ed2768e0db8b9d1Andrew Lee            Phone phone, String prefix, boolean isEmergency) {
2407d5165b05c851ecd47d330b600ed2768e0db8b9d1Andrew Lee        // TODO: Should use some sort of special hidden flag to decorate this account as
2408d5165b05c851ecd47d330b600ed2768e0db8b9d1Andrew Lee        // an emergency-only account
2409d3edc2292d969ecf8df96281c50e1a8f7a3fc777Brad Ebinger        String id = isEmergency ? EMERGENCY_ACCOUNT_HANDLE_ID : prefix +
24104fe48111c7d1f9410e65ad7abdf6e29879e09d16Brad Ebinger                String.valueOf(phone.getFullIccSerialNumber());
2411e53a064be1bcea3ec2acb3c7681fa9a2762f4e3eNancy Chen        return makePstnPhoneAccountHandleWithPrefix(id, prefix, isEmergency);
2412e53a064be1bcea3ec2acb3c7681fa9a2762f4e3eNancy Chen    }
2413e53a064be1bcea3ec2acb3c7681fa9a2762f4e3eNancy Chen
2414e53a064be1bcea3ec2acb3c7681fa9a2762f4e3eNancy Chen    public static PhoneAccountHandle makePstnPhoneAccountHandleWithPrefix(
2415e53a064be1bcea3ec2acb3c7681fa9a2762f4e3eNancy Chen            String id, String prefix, boolean isEmergency) {
2416e53a064be1bcea3ec2acb3c7681fa9a2762f4e3eNancy Chen        ComponentName pstnConnectionServiceName = getPstnConnectionServiceName();
2417d5165b05c851ecd47d330b600ed2768e0db8b9d1Andrew Lee        return new PhoneAccountHandle(pstnConnectionServiceName, id);
2418d5165b05c851ecd47d330b600ed2768e0db8b9d1Andrew Lee    }
2419dcf40a9cc562d95f826123d8d670262c8d15e7bdStuart Scott
2420f69df96f713523a8b078aa6ef922e3e752a1a594Santos Cordon    public static int getSubIdForPhoneAccount(PhoneAccount phoneAccount) {
242121e78ace4e0366ad2bc7f39406b7fa8dff2bd407Santos Cordon        if (phoneAccount != null
242221e78ace4e0366ad2bc7f39406b7fa8dff2bd407Santos Cordon                && phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
242321e78ace4e0366ad2bc7f39406b7fa8dff2bd407Santos Cordon            return getSubIdForPhoneAccountHandle(phoneAccount.getAccountHandle());
242421e78ace4e0366ad2bc7f39406b7fa8dff2bd407Santos Cordon        }
242521e78ace4e0366ad2bc7f39406b7fa8dff2bd407Santos Cordon        return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
242621e78ace4e0366ad2bc7f39406b7fa8dff2bd407Santos Cordon    }
242721e78ace4e0366ad2bc7f39406b7fa8dff2bd407Santos Cordon
242821e78ace4e0366ad2bc7f39406b7fa8dff2bd407Santos Cordon    public static int getSubIdForPhoneAccountHandle(PhoneAccountHandle handle) {
242931f9ba14fc404ce4baa7e5cba6bad84ebe4bf124Nancy Chen        Phone phone = getPhoneForPhoneAccountHandle(handle);
243031f9ba14fc404ce4baa7e5cba6bad84ebe4bf124Nancy Chen        if (phone != null) {
243131f9ba14fc404ce4baa7e5cba6bad84ebe4bf124Nancy Chen            return phone.getSubId();
2432f69df96f713523a8b078aa6ef922e3e752a1a594Santos Cordon        }
2433f69df96f713523a8b078aa6ef922e3e752a1a594Santos Cordon        return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
2434f69df96f713523a8b078aa6ef922e3e752a1a594Santos Cordon    }
2435f69df96f713523a8b078aa6ef922e3e752a1a594Santos Cordon
2436845f699e273a2490faec1bd13843e90f23413cc8Ta-wei Yen    public static Phone getPhoneForPhoneAccountHandle(PhoneAccountHandle handle) {
243731f9ba14fc404ce4baa7e5cba6bad84ebe4bf124Nancy Chen        if (handle != null && handle.getComponentName().equals(getPstnConnectionServiceName())) {
243831f9ba14fc404ce4baa7e5cba6bad84ebe4bf124Nancy Chen            return getPhoneFromIccId(handle.getId());
243931f9ba14fc404ce4baa7e5cba6bad84ebe4bf124Nancy Chen        }
244031f9ba14fc404ce4baa7e5cba6bad84ebe4bf124Nancy Chen        return null;
244131f9ba14fc404ce4baa7e5cba6bad84ebe4bf124Nancy Chen    }
244231f9ba14fc404ce4baa7e5cba6bad84ebe4bf124Nancy Chen
244331f9ba14fc404ce4baa7e5cba6bad84ebe4bf124Nancy Chen
2444e53a064be1bcea3ec2acb3c7681fa9a2762f4e3eNancy Chen    /**
2445e53a064be1bcea3ec2acb3c7681fa9a2762f4e3eNancy Chen     * Determine if a given phone account corresponds to an active SIM
2446e53a064be1bcea3ec2acb3c7681fa9a2762f4e3eNancy Chen     *
2447e53a064be1bcea3ec2acb3c7681fa9a2762f4e3eNancy Chen     * @param sm An instance of the subscription manager so it is not recreated for each calling of
2448e53a064be1bcea3ec2acb3c7681fa9a2762f4e3eNancy Chen     * this method.
2449e53a064be1bcea3ec2acb3c7681fa9a2762f4e3eNancy Chen     * @param handle The handle for the phone account to check
2450e53a064be1bcea3ec2acb3c7681fa9a2762f4e3eNancy Chen     * @return {@code true} If there is an active SIM for this phone account,
2451e53a064be1bcea3ec2acb3c7681fa9a2762f4e3eNancy Chen     * {@code false} otherwise.
2452e53a064be1bcea3ec2acb3c7681fa9a2762f4e3eNancy Chen     */
2453e53a064be1bcea3ec2acb3c7681fa9a2762f4e3eNancy Chen    public static boolean isPhoneAccountActive(SubscriptionManager sm, PhoneAccountHandle handle) {
2454e53a064be1bcea3ec2acb3c7681fa9a2762f4e3eNancy Chen        return sm.getActiveSubscriptionInfoForIccIndex(handle.getId()) != null;
2455e53a064be1bcea3ec2acb3c7681fa9a2762f4e3eNancy Chen    }
2456e53a064be1bcea3ec2acb3c7681fa9a2762f4e3eNancy Chen
2457f69df96f713523a8b078aa6ef922e3e752a1a594Santos Cordon    private static ComponentName getPstnConnectionServiceName() {
24584c8f3c63b75ba080ab697b2e8e0f1e3f732dda74Tony Mak        return PSTN_CONNECTION_SERVICE_COMPONENT;
2459f69df96f713523a8b078aa6ef922e3e752a1a594Santos Cordon    }
2460f69df96f713523a8b078aa6ef922e3e752a1a594Santos Cordon
246180855d56b0e0ca102371a56285c9f259f2e5f426Santos Cordon    private static Phone getPhoneFromIccId(String iccId) {
246280855d56b0e0ca102371a56285c9f259f2e5f426Santos Cordon        if (!TextUtils.isEmpty(iccId)) {
246380855d56b0e0ca102371a56285c9f259f2e5f426Santos Cordon            for (Phone phone : PhoneFactory.getPhones()) {
24644fe48111c7d1f9410e65ad7abdf6e29879e09d16Brad Ebinger                String phoneIccId = phone.getFullIccSerialNumber();
246580855d56b0e0ca102371a56285c9f259f2e5f426Santos Cordon                if (iccId.equals(phoneIccId)) {
246680855d56b0e0ca102371a56285c9f259f2e5f426Santos Cordon                    return phone;
246780855d56b0e0ca102371a56285c9f259f2e5f426Santos Cordon                }
246880855d56b0e0ca102371a56285c9f259f2e5f426Santos Cordon            }
246980855d56b0e0ca102371a56285c9f259f2e5f426Santos Cordon        }
247080855d56b0e0ca102371a56285c9f259f2e5f426Santos Cordon        return null;
247180855d56b0e0ca102371a56285c9f259f2e5f426Santos Cordon    }
247280855d56b0e0ca102371a56285c9f259f2e5f426Santos Cordon
2473dcf40a9cc562d95f826123d8d670262c8d15e7bdStuart Scott    /**
2474dcf40a9cc562d95f826123d8d670262c8d15e7bdStuart Scott     * Register ICC status for all phones.
2475dcf40a9cc562d95f826123d8d670262c8d15e7bdStuart Scott     */
2476dcf40a9cc562d95f826123d8d670262c8d15e7bdStuart Scott    static final void registerIccStatus(Handler handler, int event) {
2477dcf40a9cc562d95f826123d8d670262c8d15e7bdStuart Scott        for (Phone phone : PhoneFactory.getPhones()) {
2478dcf40a9cc562d95f826123d8d670262c8d15e7bdStuart Scott            IccCard sim = phone.getIccCard();
2479dcf40a9cc562d95f826123d8d670262c8d15e7bdStuart Scott            if (sim != null) {
2480dcf40a9cc562d95f826123d8d670262c8d15e7bdStuart Scott                if (VDBG) Log.v(LOG_TAG, "register for ICC status, phone " + phone.getPhoneId());
2481dcf40a9cc562d95f826123d8d670262c8d15e7bdStuart Scott                sim.registerForNetworkLocked(handler, event, phone);
2482dcf40a9cc562d95f826123d8d670262c8d15e7bdStuart Scott            }
2483dcf40a9cc562d95f826123d8d670262c8d15e7bdStuart Scott        }
2484dcf40a9cc562d95f826123d8d670262c8d15e7bdStuart Scott    }
2485dcf40a9cc562d95f826123d8d670262c8d15e7bdStuart Scott
2486dcf40a9cc562d95f826123d8d670262c8d15e7bdStuart Scott    /**
2487dcf40a9cc562d95f826123d8d670262c8d15e7bdStuart Scott     * Set the radio power on/off state for all phones.
2488dcf40a9cc562d95f826123d8d670262c8d15e7bdStuart Scott     *
2489dcf40a9cc562d95f826123d8d670262c8d15e7bdStuart Scott     * @param enabled true means on, false means off.
2490dcf40a9cc562d95f826123d8d670262c8d15e7bdStuart Scott     */
2491dcf40a9cc562d95f826123d8d670262c8d15e7bdStuart Scott    static final void setRadioPower(boolean enabled) {
2492dcf40a9cc562d95f826123d8d670262c8d15e7bdStuart Scott        for (Phone phone : PhoneFactory.getPhones()) {
2493dcf40a9cc562d95f826123d8d670262c8d15e7bdStuart Scott            phone.setRadioPower(enabled);
2494dcf40a9cc562d95f826123d8d670262c8d15e7bdStuart Scott        }
2495dcf40a9cc562d95f826123d8d670262c8d15e7bdStuart Scott    }
24967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon}
2497