PhoneUtils.java revision f69df96f713523a8b078aa6ef922e3e752a1a594
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;
337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.os.RemoteException;
347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.os.SystemProperties;
354d45d1cf58a2003378fd35912d6d73a00001bf06Tyler Gunnimport android.telecom.PhoneAccount;
36d5165b05c851ecd47d330b600ed2768e0db8b9d1Andrew Leeimport android.telecom.PhoneAccountHandle;
374d45d1cf58a2003378fd35912d6d73a00001bf06Tyler Gunnimport android.telecom.VideoProfile;
387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.telephony.PhoneNumberUtils;
39f69df96f713523a8b078aa6ef922e3e752a1a594Santos Cordonimport android.telephony.SubscriptionManager;
407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.text.TextUtils;
417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.util.Log;
42b3ee4dc3dd39ebe765ebe6b535b3900bb95813d8Andrew Leeimport android.view.ContextThemeWrapper;
437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.view.KeyEvent;
447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.view.LayoutInflater;
457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.view.View;
467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.view.WindowManager;
477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.widget.EditText;
487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.widget.Toast;
497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport com.android.internal.telephony.Call;
517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport com.android.internal.telephony.CallManager;
527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport com.android.internal.telephony.CallStateException;
537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport com.android.internal.telephony.CallerInfo;
547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport com.android.internal.telephony.CallerInfoAsyncQuery;
557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport com.android.internal.telephony.Connection;
56dcf40a9cc562d95f826123d8d670262c8d15e7bdStuart Scottimport com.android.internal.telephony.IccCard;
577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport com.android.internal.telephony.MmiCode;
587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport com.android.internal.telephony.Phone;
597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport com.android.internal.telephony.PhoneConstants;
60dcf40a9cc562d95f826123d8d670262c8d15e7bdStuart Scottimport com.android.internal.telephony.PhoneFactory;
617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport com.android.internal.telephony.TelephonyCapabilities;
627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport com.android.internal.telephony.TelephonyProperties;
637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport com.android.internal.telephony.sip.SipPhone;
6469a691914e9b013a7ff52c129d8466c152ed7239Santos Cordonimport com.android.phone.CallGatewayManager.RawGatewayInfo;
65d5165b05c851ecd47d330b600ed2768e0db8b9d1Andrew Leeimport com.android.services.telephony.TelephonyConnectionService;
667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport java.util.Arrays;
687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport java.util.List;
697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon/**
717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon * Misc utilities for the Phone app.
727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon */
737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonpublic class PhoneUtils {
747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static final String LOG_TAG = "PhoneUtils";
757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2);
767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    // Do not check in with VDBG = true, since that may write PII to the system log.
787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static final boolean VDBG = false;
797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /** Control stack trace for Audio Mode settings */
817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static final boolean DBG_SETAUDIOMODE_STACK = false;
827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /** Identifier for the "Add Call" intent extra. */
847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static final String ADD_CALL_MODE_KEY = "add_call_mode";
857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    // Return codes from placeCall()
877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static final int CALL_STATUS_DIALED = 0;  // The number was successfully dialed
887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static final int CALL_STATUS_DIALED_MMI = 1;  // The specified number was an MMI code
897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static final int CALL_STATUS_FAILED = 2;  // The call failed
907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    // State of the Phone's audio modes
927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    // Each state can move to the other states, but within the state only certain
937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    //  transitions for AudioManager.setMode() are allowed.
947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static final int AUDIO_IDLE = 0;  /** audio behaviour at phone idle */
957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static final int AUDIO_RINGING = 1;  /** audio behaviour while ringing */
967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static final int AUDIO_OFFHOOK = 2;  /** audio behaviour while in call. */
977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    // USSD string length for MMI operations
997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static final int MIN_USSD_LEN = 1;
1007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static final int MAX_USSD_LEN = 160;
1017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /** Speaker state, persisting between wired headset connection events */
1037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static boolean sIsSpeakerEnabled = false;
1047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /** Static handler for the connection/mute tracking */
1067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static ConnectionHandler mConnectionHandler;
1077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /** Phone state changed event*/
1097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static final int PHONE_STATE_CHANGED = -1;
1107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
111a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu    /** check status then decide whether answerCall */
112a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu    private static final int MSG_CHECK_STATUS_ANSWERCALL = 100;
113a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu
114a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu    /** poll phone DISCONNECTING status interval */
115a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu    private static final int DISCONNECTING_POLLING_INTERVAL_MS = 200;
116a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu
117a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu    /** poll phone DISCONNECTING status times limit */
118a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu    private static final int DISCONNECTING_POLLING_TIMES_LIMIT = 8;
119a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu
1207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /** Define for not a special CNAP string */
1217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static final int CNAP_SPECIAL_CASE_NO = -1;
1227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /** Noise suppression status as selected by user */
1247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static boolean sIsNoiseSuppressionEnabled = true;
1257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
126e0f2b791135a88de7930e4339686fd5b79e53a9fYorke Lee    /**
127e0f2b791135a88de7930e4339686fd5b79e53a9fYorke Lee     * Theme to use for dialogs displayed by utility methods in this class. This is needed
128e0f2b791135a88de7930e4339686fd5b79e53a9fYorke Lee     * because these dialogs are displayed using the application context, which does not resolve
129e0f2b791135a88de7930e4339686fd5b79e53a9fYorke Lee     * the dialog theme correctly.
130e0f2b791135a88de7930e4339686fd5b79e53a9fYorke Lee     */
131e0f2b791135a88de7930e4339686fd5b79e53a9fYorke Lee    private static final int THEME = AlertDialog.THEME_DEVICE_DEFAULT_LIGHT;
132e0f2b791135a88de7930e4339686fd5b79e53a9fYorke Lee
133a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu    private static class FgRingCalls {
134a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu        private Call fgCall;
135a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu        private Call ringing;
136a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu        public FgRingCalls(Call fg, Call ring) {
137a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu            fgCall = fg;
138a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu            ringing = ring;
139a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu        }
140a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu    }
141a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu
14237abbab24baec145cdf995693be96cd7162b0c06Etan Cohen    /** USSD information used to aggregate all USSD messages */
14337abbab24baec145cdf995693be96cd7162b0c06Etan Cohen    private static AlertDialog sUssdDialog = null;
14437abbab24baec145cdf995693be96cd7162b0c06Etan Cohen    private static StringBuilder sUssdMsg = new StringBuilder();
14537abbab24baec145cdf995693be96cd7162b0c06Etan Cohen
1467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
1477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Handler that tracks the connections and updates the value of the
1487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Mute settings for each connection as needed.
1497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
1507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static class ConnectionHandler extends Handler {
1517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        @Override
1527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        public void handleMessage(Message msg) {
1537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            switch (msg.what) {
154a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                case MSG_CHECK_STATUS_ANSWERCALL:
155a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                    FgRingCalls frC = (FgRingCalls) msg.obj;
156a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                    // wait for finishing disconnecting
157a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                    // before check the ringing call state
158a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                    if ((frC.fgCall != null) &&
159a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                        (frC.fgCall.getState() == Call.State.DISCONNECTING) &&
160a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                        (msg.arg1 < DISCONNECTING_POLLING_TIMES_LIMIT)) {
161a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                        Message retryMsg =
162a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                            mConnectionHandler.obtainMessage(MSG_CHECK_STATUS_ANSWERCALL);
163a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                        retryMsg.arg1 = 1 + msg.arg1;
164a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                        retryMsg.obj = msg.obj;
165a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                        mConnectionHandler.sendMessageDelayed(retryMsg,
166a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                            DISCONNECTING_POLLING_INTERVAL_MS);
167a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                    // since hangupActiveCall() also accepts the ringing call
168a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                    // check if the ringing call was already answered or not
169a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                    // only answer it when the call still is ringing
170a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                    } else if (frC.ringing.isRinging()) {
171a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                        if (msg.arg1 == DISCONNECTING_POLLING_TIMES_LIMIT) {
172a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                            Log.e(LOG_TAG, "DISCONNECTING time out");
173a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                        }
174a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                        answerCall(frC.ringing);
175a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                    }
176a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu                    break;
1777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
1787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
1797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
1807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
1827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Register the ConnectionHandler with the phone, to receive connection events
1837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
1847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public static void initializeConnectionHandler(CallManager cm) {
1857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (mConnectionHandler == null) {
1867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            mConnectionHandler = new ConnectionHandler();
1877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
1887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // pass over cm as user.obj
1907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        cm.registerForPreciseCallStateChanged(mConnectionHandler, PHONE_STATE_CHANGED, cm);
1917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
1937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /** This class is never instantiated. */
1957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private PhoneUtils() {
1967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
1977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
1997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Answer the currently-ringing call.
2007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
2017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return true if we answered the call, or false if there wasn't
2027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *         actually a ringing incoming call, or some other error occurred.
2037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
2047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @see #answerAndEndHolding(CallManager, Call)
2057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @see #answerAndEndActive(CallManager, Call)
2067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
2077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /* package */ static boolean answerCall(Call ringingCall) {
2087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        log("answerCall(" + ringingCall + ")...");
2097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final PhoneGlobals app = PhoneGlobals.getInstance();
2107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final CallNotifier notifier = app.notifier;
2117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final Phone phone = ringingCall.getPhone();
2137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final boolean phoneIsCdma = (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA);
2147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        boolean answered = false;
2157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        IBluetoothHeadsetPhone btPhone = null;
2167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (phoneIsCdma) {
2187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // Stop any signalInfo tone being played when a Call waiting gets answered
2197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (ringingCall.getState() == Call.State.WAITING) {
2207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                notifier.stopSignalInfoTone();
2217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
2227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
2237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (ringingCall != null && ringingCall.isRinging()) {
2257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG) log("answerCall: call state = " + ringingCall.getState());
2267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            try {
2277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (phoneIsCdma) {
2287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    if (app.cdmaPhoneCallState.getCurrentCallState()
2297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            == CdmaPhoneCallState.PhoneCallState.IDLE) {
2307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        // This is the FIRST incoming call being answered.
2317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        // Set the Phone Call State to SINGLE_ACTIVE
2327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        app.cdmaPhoneCallState.setCurrentCallState(
2337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                CdmaPhoneCallState.PhoneCallState.SINGLE_ACTIVE);
2347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    } else {
2357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        // This is the CALL WAITING call being answered.
2367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        // Set the Phone Call State to CONF_CALL
2377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        app.cdmaPhoneCallState.setCurrentCallState(
2387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                CdmaPhoneCallState.PhoneCallState.CONF_CALL);
2397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        // Enable "Add Call" option after answering a Call Waiting as the user
2407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        // should be allowed to add another call in case one of the parties
2417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        // drops off
2427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        app.cdmaPhoneCallState.setAddCallMenuStateAfterCallWaiting(true);
24313fed9f2657f9bcc8c4b54783cf165cd4d7b57c1Santos Cordon                    }
2447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
2457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                final boolean isRealIncomingCall = isRealIncomingCall(ringingCall.getState());
2477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //if (DBG) log("sPhone.acceptCall");
2497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                app.mCM.acceptCall(ringingCall);
2507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                answered = true;
2517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                setAudioMode();
2537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // Check is phone in any dock, and turn on speaker accordingly
2557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                final boolean speakerActivated = activateSpeakerIfDocked(phone);
2567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
25727a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon                final BluetoothManager btManager = app.getBluetoothManager();
25827a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon
2597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // When answering a phone call, the user will move the phone near to her/his ear
2607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // and start conversation, without checking its speaker status. If some other
2617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // application turned on the speaker mode before the call and didn't turn it off,
2627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // Phone app would need to be responsible for the speaker phone.
2637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // Here, we turn off the speaker if
2647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // - the phone call is the first in-coming call,
2657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // - we did not activate speaker by ourselves during the process above, and
2667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // - Bluetooth headset is not in use.
2677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (isRealIncomingCall && !speakerActivated && isSpeakerOn(app)
26827a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon                        && !btManager.isBluetoothHeadsetAudioOn()) {
2697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // This is not an error but might cause users' confusion. Add log just in case.
2707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    Log.i(LOG_TAG, "Forcing speaker off due to new incoming call...");
2717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    turnOnSpeaker(app, false, true);
2727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
2737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            } catch (CallStateException ex) {
2747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Log.w(LOG_TAG, "answerCall: caught " + ex, ex);
2757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (phoneIsCdma) {
2777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // restore the cdmaPhoneCallState and btPhone.cdmaSetSecondCallState:
2787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    app.cdmaPhoneCallState.setCurrentCallState(
2797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            app.cdmaPhoneCallState.getPreviousCallState());
2807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    if (btPhone != null) {
2817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        try {
2827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            btPhone.cdmaSetSecondCallState(false);
2837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        } catch (RemoteException e) {
2847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            Log.e(LOG_TAG, Log.getStackTraceString(new Throwable()));
2857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        }
2867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    }
2877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
2887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
2897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
2907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return answered;
2917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
2927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
294de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon     * Hangs up all active calls.
295de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon     */
296de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon    static void hangupAllCalls(CallManager cm) {
297de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon        final Call ringing = cm.getFirstActiveRingingCall();
298de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon        final Call fg = cm.getActiveFgCall();
299de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon        final Call bg = cm.getFirstActiveBgCall();
300de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon
301de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon        // We go in reverse order, BG->FG->RINGING because hanging up a ringing call or an active
302de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon        // call can move a bg call to a fg call which would force us to loop over each call
303de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon        // several times.  This ordering works best to ensure we dont have any more calls.
304de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon        if (bg != null && !bg.isIdle()) {
305de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon            hangup(bg);
306de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon        }
307de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon        if (fg != null && !fg.isIdle()) {
308de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon            hangup(fg);
309de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon        }
310de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon        if (ringing != null && !ringing.isIdle()) {
311de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon            hangupRingingCall(fg);
312de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon        }
313de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon    }
314de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon
315de10b75b2802b0a74de17a972d007efc0fc19f55Santos Cordon    /**
3167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Smart "hang up" helper method which hangs up exactly one connection,
3177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * based on the current Phone state, as follows:
3187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * <ul>
3197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * <li>If there's a ringing call, hang that up.
3207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * <li>Else if there's a foreground call, hang that up.
3217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * <li>Else if there's a background call, hang that up.
3227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * <li>Otherwise do nothing.
3237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * </ul>
3247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return true if we successfully hung up, or false
3257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *              if there were no active calls at all.
3267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
3277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static boolean hangup(CallManager cm) {
3287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        boolean hungup = false;
3297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Call ringing = cm.getFirstActiveRingingCall();
3307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Call fg = cm.getActiveFgCall();
3317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Call bg = cm.getFirstActiveBgCall();
3327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
3337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (!ringing.isIdle()) {
3347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            log("hangup(): hanging up ringing call");
3357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            hungup = hangupRingingCall(ringing);
3367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else if (!fg.isIdle()) {
3377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            log("hangup(): hanging up foreground call");
3387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            hungup = hangup(fg);
3397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else if (!bg.isIdle()) {
3407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            log("hangup(): hanging up background call");
3417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            hungup = hangup(bg);
3427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
3437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // No call to hang up!  This is unlikely in normal usage,
3447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // since the UI shouldn't be providing an "End call" button in
3457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // the first place.  (But it *can* happen, rarely, if an
3467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // active call happens to disconnect on its own right when the
3477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // user is trying to hang up..)
3487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            log("hangup(): no active call to hang up");
3497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
3507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("==> hungup = " + hungup);
3517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
3527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return hungup;
3537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
3547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
3557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static boolean hangupRingingCall(Call ringing) {
3567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("hangup ringing call");
3577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        int phoneType = ringing.getPhone().getPhoneType();
3587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Call.State state = ringing.getState();
3597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
3607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (state == Call.State.INCOMING) {
3617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // Regular incoming call (with no other active calls)
3627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            log("hangupRingingCall(): regular incoming call: hangup()");
3637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return hangup(ringing);
3647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
3657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // Unexpected state: the ringing call isn't INCOMING or
3667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // WAITING, so there's no reason to have called
3677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // hangupRingingCall() in the first place.
3687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // (Presumably the incoming call went away at the exact moment
3697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // we got here, so just do nothing.)
3707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Log.w(LOG_TAG, "hangupRingingCall: no INCOMING or WAITING call");
3717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return false;
3727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
3737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
3747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
3757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static boolean hangupActiveCall(Call foreground) {
3767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("hangup active call");
3777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return hangup(foreground);
3787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
3797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
3807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static boolean hangupHoldingCall(Call background) {
3817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("hangup holding call");
3827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return hangup(background);
3837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
3847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
3857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
3867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Used in CDMA phones to end the complete Call session
3877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param phone the Phone object.
3887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return true if *any* call was successfully hung up
3897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
3907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static boolean hangupRingingAndActive(Phone phone) {
3917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        boolean hungUpRingingCall = false;
3927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        boolean hungUpFgCall = false;
3937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Call ringingCall = phone.getRingingCall();
3947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Call fgCall = phone.getForegroundCall();
3957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
3967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Hang up any Ringing Call
3977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (!ringingCall.isIdle()) {
3987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            log("hangupRingingAndActive: Hang up Ringing Call");
3997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            hungUpRingingCall = hangupRingingCall(ringingCall);
4007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
4017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Hang up any Active Call
4037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (!fgCall.isIdle()) {
4047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            log("hangupRingingAndActive: Hang up Foreground Call");
4057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            hungUpFgCall = hangupActiveCall(fgCall);
4067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
4077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return hungUpRingingCall || hungUpFgCall;
4097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
4107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
4127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Trivial wrapper around Call.hangup(), except that we return a
4137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * boolean success code rather than throwing CallStateException on
4147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * failure.
4157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
4167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return true if the call was successfully hung up, or false
4177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *         if the call wasn't actually active.
4187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
4197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static boolean hangup(Call call) {
4207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        try {
4217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            CallManager cm = PhoneGlobals.getInstance().mCM;
4227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (call.getState() == Call.State.ACTIVE && cm.hasActiveBgCall()) {
4247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // handle foreground call hangup while there is background call
4257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                log("- hangup(Call): hangupForegroundResumeBackground...");
4267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                cm.hangupForegroundResumeBackground(cm.getFirstActiveBgCall());
4277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            } else {
4287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                log("- hangup(Call): regular hangup()...");
4297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                call.hangup();
4307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
4317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return true;
4327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } catch (CallStateException ex) {
4337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Log.e(LOG_TAG, "Call hangup: caught " + ex, ex);
4347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
4357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return false;
4377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
4387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
4407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Trivial wrapper around Connection.hangup(), except that we silently
4417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * do nothing (rather than throwing CallStateException) if the
4427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * connection wasn't actually active.
4437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
4447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static void hangup(Connection c) {
4457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        try {
4467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (c != null) {
4477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                c.hangup();
4487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
4497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } catch (CallStateException ex) {
4507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Log.w(LOG_TAG, "Connection hangup: caught " + ex, ex);
4517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
4527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
4537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static boolean answerAndEndHolding(CallManager cm, Call ringing) {
4557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("end holding & answer waiting: 1");
4567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (!hangupHoldingCall(cm.getFirstActiveBgCall())) {
4577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Log.e(LOG_TAG, "end holding failed!");
4587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return false;
4597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
4607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("end holding & answer waiting: 2");
4627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return answerCall(ringing);
4637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
4657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
4677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Answers the incoming call specified by "ringing", and ends the currently active phone call.
4687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
4697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * This method is useful when's there's an incoming call which we cannot manage with the
4707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * current call. e.g. when you are having a phone call with CDMA network and has received
4717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * a SIP call, then we won't expect our telephony can manage those phone calls simultaneously.
4727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Note that some types of network may allow multiple phone calls at once; GSM allows to hold
4737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * an ongoing phone call, so we don't need to end the active call. The caller of this method
4747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * needs to check if the network allows multiple phone calls or not.
4757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
4767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @see #answerCall(Call)
4777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @see InCallScreen#internalAnswerCall()
4787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
4797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /* package */ static boolean answerAndEndActive(CallManager cm, Call ringing) {
4807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("answerAndEndActive()...");
4817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Unlike the answerCall() method, we *don't* need to stop the
4837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // ringer or change audio modes here since the user is already
4847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // in-call, which means that the audio mode is already set
4857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // correctly, and that we wouldn't have started the ringer in the
4867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // first place.
4877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // hanging up the active call also accepts the waiting call
4897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // while active call and waiting call are from the same phone
4907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // i.e. both from GSM phone
491a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu        Call fgCall = cm.getActiveFgCall();
492a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu        if (!hangupActiveCall(fgCall)) {
4937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Log.w(LOG_TAG, "end active call failed!");
4947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return false;
4957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
4967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
497a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu        mConnectionHandler.removeMessages(MSG_CHECK_STATUS_ANSWERCALL);
498a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu        Message msg = mConnectionHandler.obtainMessage(MSG_CHECK_STATUS_ANSWERCALL);
499a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu        msg.arg1 = 1;
500a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu        msg.obj = new FgRingCalls(fgCall, ringing);
501a4915c7016996a0df4cb34bff1607e49fbd6d403Zhihai Xu        mConnectionHandler.sendMessage(msg);
5027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return true;
5047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
5057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
5077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * For a CDMA phone, advance the call state upon making a new
5087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * outgoing call.
5097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
5107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * <pre>
5117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *   IDLE -> SINGLE_ACTIVE
5127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * or
5137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *   SINGLE_ACTIVE -> THRWAY_ACTIVE
5147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * </pre>
5157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param app The phone instance.
5167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
517ad1ed6d23c4a999a41bb73b8243009e32f96d7dfSantos Cordon    private static void updateCdmaCallStateOnNewOutgoingCall(PhoneGlobals app,
518ad1ed6d23c4a999a41bb73b8243009e32f96d7dfSantos Cordon            Connection connection) {
5197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (app.cdmaPhoneCallState.getCurrentCallState() ==
5207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            CdmaPhoneCallState.PhoneCallState.IDLE) {
5217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // This is the first outgoing call. Set the Phone Call State to ACTIVE
5227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            app.cdmaPhoneCallState.setCurrentCallState(
5237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                CdmaPhoneCallState.PhoneCallState.SINGLE_ACTIVE);
5247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
5257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // This is the second outgoing call. Set the Phone Call State to 3WAY
5267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            app.cdmaPhoneCallState.setCurrentCallState(
5277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE);
528ad1ed6d23c4a999a41bb73b8243009e32f96d7dfSantos Cordon
529da120f4e3d32ca97c5b4c21d6c505d834a29ab8dSantos Cordon            // TODO: Remove this code.
53023d9ed758fbe78e4afd4067e6845bcaf3387bca7Sailesh Nepal            //app.getCallModeler().setCdmaOutgoing3WayCall(connection);
5317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
5327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
5337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
53569a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon     * @see placeCall below
53669a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon     */
53769a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon    public static int placeCall(Context context, Phone phone, String number, Uri contactRef,
53869a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon            boolean isEmergencyCall) {
53969a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon        return placeCall(context, phone, number, contactRef, isEmergencyCall,
54069a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon                CallGatewayManager.EMPTY_INFO, null);
54169a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon    }
54269a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon
54369a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon    /**
5447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Dial the number using the phone passed in.
5457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
5467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * If the connection is establised, this method issues a sync call
5477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * that may block to query the caller info.
5487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * TODO: Change the logic to use the async query.
5497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
5507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param context To perform the CallerInfo query.
5517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param phone the Phone object.
5527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param number to be dialed as requested by the user. This is
5537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * NOT the phone number to connect to. It is used only to build the
5547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * call card and to update the call log. See above for restrictions.
5557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param contactRef that triggered the call. Typically a 'tel:'
5567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * uri but can also be a 'content://contacts' one.
5577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param isEmergencyCall indicates that whether or not this is an
5587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * emergency call
5597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param gatewayUri Is the address used to setup the connection, null
5607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * if not using a gateway
56169a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon     * @param callGateway Class for setting gateway data on a successful call.
5627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
5637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return either CALL_STATUS_DIALED or CALL_STATUS_FAILED
5647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
56569a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon    public static int placeCall(Context context, Phone phone, String number, Uri contactRef,
56669a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon            boolean isEmergencyCall, RawGatewayInfo gatewayInfo, CallGatewayManager callGateway) {
56769a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon        final Uri gatewayUri = gatewayInfo.gatewayUri;
56869a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon
5697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (VDBG) {
5707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            log("placeCall()... number: '" + number + "'"
5717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    + ", GW:'" + gatewayUri + "'"
5727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    + ", contactRef:" + contactRef
5737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    + ", isEmergencyCall: " + isEmergencyCall);
5747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
5757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            log("placeCall()... number: " + toLogSafePhoneNumber(number)
5767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    + ", GW: " + (gatewayUri != null ? "non-null" : "null")
5777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    + ", emergency? " + isEmergencyCall);
5787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
5797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final PhoneGlobals app = PhoneGlobals.getInstance();
5807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        boolean useGateway = false;
5827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (null != gatewayUri &&
5837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            !isEmergencyCall &&
5847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            PhoneUtils.isRoutableViaGateway(number)) {  // Filter out MMI, OTA and other codes.
5857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            useGateway = true;
5867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
5877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        int status = CALL_STATUS_DIALED;
5897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Connection connection;
5907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        String numberToDial;
5917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (useGateway) {
5927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // TODO: 'tel' should be a constant defined in framework base
5937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // somewhere (it is in webkit.)
594137458b4bf3516941483e59c123c22cbee27ed43Jay Shrauner            if (null == gatewayUri || !PhoneAccount.SCHEME_TEL.equals(gatewayUri.getScheme())) {
5957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Log.e(LOG_TAG, "Unsupported URL:" + gatewayUri);
5967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                return CALL_STATUS_FAILED;
5977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
5987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // We can use getSchemeSpecificPart because we don't allow #
6007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // in the gateway numbers (treated a fragment delim.) However
6017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // if we allow more complex gateway numbers sequence (with
6027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // passwords or whatnot) that use #, this may break.
6037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // TODO: Need to support MMI codes.
6047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            numberToDial = gatewayUri.getSchemeSpecificPart();
6057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
6067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            numberToDial = number;
6077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
6087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
6097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Remember if the phone state was in IDLE state before this call.
6107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // After calling CallManager#dial(), getState() will return different state.
6117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final boolean initiallyIdle = app.mCM.getState() == PhoneConstants.State.IDLE;
6127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
6137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        try {
61476f3b4ec8d9bcb8926db1b3e4fb2d1e969b09fbbIhab Awad            connection = app.mCM.dial(phone, numberToDial, VideoProfile.VideoState.AUDIO_ONLY);
6157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } catch (CallStateException ex) {
6167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // CallStateException means a new outgoing call is not currently
6177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // possible: either no more call slots exist, or there's another
6187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // call already in the process of dialing or ringing.
6197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Log.w(LOG_TAG, "Exception from app.mCM.dial()", ex);
6207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return CALL_STATUS_FAILED;
6217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
6227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // Note that it's possible for CallManager.dial() to return
6237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // null *without* throwing an exception; that indicates that
6247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // we dialed an MMI (see below).
6257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
6267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
6277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        int phoneType = phone.getPhoneType();
6287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
6297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // On GSM phones, null is returned for MMI codes
6307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (null == connection) {
631f77a3397cb022cb6aa8e7e72a5b14ba29a99563fSantos Cordon            status = CALL_STATUS_FAILED;
6327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
63310f1c6a97074b981b08bb804a3568c17ec3890a5Tyler Gunn            // Now that the call is successful, we can save the gateway info for the call
63410f1c6a97074b981b08bb804a3568c17ec3890a5Tyler Gunn            if (callGateway != null) {
63510f1c6a97074b981b08bb804a3568c17ec3890a5Tyler Gunn                callGateway.setGatewayInfoForConnection(connection, gatewayInfo);
63610f1c6a97074b981b08bb804a3568c17ec3890a5Tyler Gunn            }
63710f1c6a97074b981b08bb804a3568c17ec3890a5Tyler Gunn
6387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
639ad1ed6d23c4a999a41bb73b8243009e32f96d7dfSantos Cordon                updateCdmaCallStateOnNewOutgoingCall(app, connection);
6407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
6417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
6427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (gatewayUri == null) {
6437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // phone.dial() succeeded: we're now in a normal phone call.
6447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // attach the URI to the CallerInfo Object if it is there,
6457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // otherwise just attach the Uri Reference.
6467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // if the uri does not have a "content" scheme, then we treat
6477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // it as if it does NOT have a unique reference.
6487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                String content = context.getContentResolver().SCHEME_CONTENT;
6497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if ((contactRef != null) && (contactRef.getScheme().equals(content))) {
6507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    Object userDataObject = connection.getUserData();
6517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    if (userDataObject == null) {
6527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        connection.setUserData(contactRef);
6537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    } else {
6547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        // TODO: This branch is dead code, we have
6557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        // just created the connection which has
6567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        // no user data (null) by default.
6577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        if (userDataObject instanceof CallerInfo) {
6587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        ((CallerInfo) userDataObject).contactRefUri = contactRef;
6597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        } else {
6607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        ((CallerInfoToken) userDataObject).currentInfo.contactRefUri =
6617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            contactRef;
6627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        }
6637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    }
6647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
6657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
666c264cba0b6ea81b3f741d9c41a0a50b7ffd19220Santos Cordon
667e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng            startGetCallerInfo(context, connection, null, null, gatewayInfo);
668e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng
6697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            setAudioMode();
6707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
6717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG) log("about to activate speaker");
6727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // Check is phone in any dock, and turn on speaker accordingly
6737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            final boolean speakerActivated = activateSpeakerIfDocked(phone);
6747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
67527a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon            final BluetoothManager btManager = app.getBluetoothManager();
67627a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon
6777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // See also similar logic in answerCall().
6787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (initiallyIdle && !speakerActivated && isSpeakerOn(app)
67927a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon                    && !btManager.isBluetoothHeadsetAudioOn()) {
6807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // This is not an error but might cause users' confusion. Add log just in case.
6817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Log.i(LOG_TAG, "Forcing speaker off when initiating a new outgoing call...");
6827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                PhoneUtils.turnOnSpeaker(app, false, true);
6837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
6847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
6857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
6867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return status;
6877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
6887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
6897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /* package */ static String toLogSafePhoneNumber(String number) {
6907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // For unknown number, log empty string.
6917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (number == null) {
6927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return "";
6937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
6947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
6957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (VDBG) {
6967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // When VDBG is true we emit PII.
6977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return number;
6987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
6997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
7007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Do exactly same thing as Uri#toSafeString() does, which will enable us to compare
7017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // sanitized phone numbers.
7027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        StringBuilder builder = new StringBuilder();
7037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        for (int i = 0; i < number.length(); i++) {
7047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            char c = number.charAt(i);
7057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (c == '-' || c == '@' || c == '.') {
7067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                builder.append(c);
7077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            } else {
7087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                builder.append('x');
7097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
7107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
7117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return builder.toString();
7127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
7137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
7147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
7157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Wrapper function to control when to send an empty Flash command to the network.
7167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Mainly needed for CDMA networks, such as scenarios when we need to send a blank flash
7177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * to the network prior to placing a 3-way call for it to be successful.
7187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
7197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static void sendEmptyFlash(Phone phone) {
7207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {
7217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Call fgCall = phone.getForegroundCall();
7227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (fgCall.getState() == Call.State.ACTIVE) {
7237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // Send the empty flash
7247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (DBG) Log.d(LOG_TAG, "onReceive: (CDMA) sending empty flash to network");
7257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                switchHoldingAndActive(phone.getBackgroundCall());
7267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
7277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
7287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
7297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
73036ebb0d4d04346a367b7a54b178ab4f78696e95cGabriel Peal    static void swap() {
73136ebb0d4d04346a367b7a54b178ab4f78696e95cGabriel Peal        final PhoneGlobals mApp = PhoneGlobals.getInstance();
73236ebb0d4d04346a367b7a54b178ab4f78696e95cGabriel Peal        if (!okToSwapCalls(mApp.mCM)) {
73336ebb0d4d04346a367b7a54b178ab4f78696e95cGabriel Peal            // TODO: throw an error instead?
73436ebb0d4d04346a367b7a54b178ab4f78696e95cGabriel Peal            return;
73536ebb0d4d04346a367b7a54b178ab4f78696e95cGabriel Peal        }
73636ebb0d4d04346a367b7a54b178ab4f78696e95cGabriel Peal
73736ebb0d4d04346a367b7a54b178ab4f78696e95cGabriel Peal        // Swap the fg and bg calls.
73836ebb0d4d04346a367b7a54b178ab4f78696e95cGabriel Peal        // In the future we may provide some way for user to choose among
73936ebb0d4d04346a367b7a54b178ab4f78696e95cGabriel Peal        // multiple background calls, for now, always act on the first background call.
74036ebb0d4d04346a367b7a54b178ab4f78696e95cGabriel Peal        PhoneUtils.switchHoldingAndActive(mApp.mCM.getFirstActiveBgCall());
74136ebb0d4d04346a367b7a54b178ab4f78696e95cGabriel Peal    }
74236ebb0d4d04346a367b7a54b178ab4f78696e95cGabriel Peal
7437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
7447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param heldCall is the background call want to be swapped
7457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
7467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static void switchHoldingAndActive(Call heldCall) {
7477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        log("switchHoldingAndActive()...");
7487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        try {
7497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            CallManager cm = PhoneGlobals.getInstance().mCM;
7507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (heldCall.isIdle()) {
7517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // no heldCall, so it is to hold active call
7527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                cm.switchHoldingAndActive(cm.getFgPhone().getBackgroundCall());
7537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            } else {
7547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // has particular heldCall, so to switch
7557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                cm.switchHoldingAndActive(heldCall);
7567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
7577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            setAudioMode(cm);
7587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } catch (CallStateException ex) {
7597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Log.w(LOG_TAG, "switchHoldingAndActive: caught " + ex, ex);
7607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
7617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
7627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
7637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static void mergeCalls() {
7647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        mergeCalls(PhoneGlobals.getInstance().mCM);
7657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
7667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
7677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static void mergeCalls(CallManager cm) {
7687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        int phoneType = cm.getFgPhone().getPhoneType();
7697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
7707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            log("mergeCalls(): CDMA...");
7717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            PhoneGlobals app = PhoneGlobals.getInstance();
7727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (app.cdmaPhoneCallState.getCurrentCallState()
7737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    == CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE) {
7747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // Set the Phone Call State to conference
7757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                app.cdmaPhoneCallState.setCurrentCallState(
7767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        CdmaPhoneCallState.PhoneCallState.CONF_CALL);
7777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
7787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // Send flash cmd
7797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // TODO: Need to change the call from switchHoldingAndActive to
7807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // something meaningful as we are not actually trying to swap calls but
7817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // instead are merging two calls by sending a Flash command.
7827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                log("- sending flash...");
7837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                switchHoldingAndActive(cm.getFirstActiveBgCall());
7847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
7857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
7867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            try {
7877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                log("mergeCalls(): calling cm.conference()...");
7887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                cm.conference(cm.getFirstActiveBgCall());
7897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            } catch (CallStateException ex) {
7907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Log.w(LOG_TAG, "mergeCalls: caught " + ex, ex);
7917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
7927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
7937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
7947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
7957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static void separateCall(Connection c) {
7967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        try {
7977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG) log("separateCall: " + toLogSafePhoneNumber(c.getAddress()));
7987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            c.separate();
7997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } catch (CallStateException ex) {
8007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Log.w(LOG_TAG, "separateCall: caught " + ex, ex);
8017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
8027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
8037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
8047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
8057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Handle the MMIInitiate message and put up an alert that lets
8067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * the user cancel the operation, if applicable.
8077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
8087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param context context to get strings.
8097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param mmiCode the MmiCode object being started.
8107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param buttonCallbackMessage message to post when button is clicked.
8117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param previousAlert a previous alert used in this activity.
8127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return the dialog handle
8137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
8147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static Dialog displayMMIInitiate(Context context,
8157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                          MmiCode mmiCode,
8167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                          Message buttonCallbackMessage,
8177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                          Dialog previousAlert) {
8187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("displayMMIInitiate: " + mmiCode);
8197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (previousAlert != null) {
8207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            previousAlert.dismiss();
8217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
8227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
8237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // The UI paradigm we are using now requests that all dialogs have
8247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // user interaction, and that any other messages to the user should
8257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // be by way of Toasts.
8267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //
8277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // In adhering to this request, all MMI initiating "OK" dialogs
8287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // (non-cancelable MMIs) that end up being closed when the MMI
8297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // completes (thereby showing a completion dialog) are being
8307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // replaced with Toasts.
8317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //
8327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // As a side effect, moving to Toasts for the non-cancelable MMIs
8337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // also means that buttonCallbackMessage (which was tied into "OK")
8347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // is no longer invokable for these dialogs.  This is not a problem
8357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // since the only callback messages we supported were for cancelable
8367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // MMIs anyway.
8377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //
8387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // A cancelable MMI is really just a USSD request. The term
8397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // "cancelable" here means that we can cancel the request when the
8407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // system prompts us for a response, NOT while the network is
8417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // processing the MMI request.  Any request to cancel a USSD while
8427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // the network is NOT ready for a response may be ignored.
8437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //
8447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // With this in mind, we replace the cancelable alert dialog with
8457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // a progress dialog, displayed until we receive a request from
8467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // the the network.  For more information, please see the comments
8477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // in the displayMMIComplete() method below.
8487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //
8497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Anything that is NOT a USSD request is a normal MMI request,
8507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // which will bring up a toast (desribed above).
8517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
8527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        boolean isCancelable = (mmiCode != null) && mmiCode.isCancelable();
8537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
8547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (!isCancelable) {
8557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG) log("not a USSD code, displaying status toast.");
8567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            CharSequence text = context.getText(R.string.mmiStarted);
8577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Toast.makeText(context, text, Toast.LENGTH_SHORT)
8587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                .show();
8597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return null;
8607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
8617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG) log("running USSD code, displaying indeterminate progress.");
8627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
8637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // create the indeterminate progress dialog and display it.
8647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            ProgressDialog pd = new ProgressDialog(context);
8657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            pd.setMessage(context.getText(R.string.ussdRunning));
8667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            pd.setCancelable(false);
8677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            pd.setIndeterminate(true);
8687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            pd.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
8697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
8707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            pd.show();
8717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
8727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return pd;
8737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
8747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
8757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
8767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
8777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
8787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Handle the MMIComplete message and fire off an intent to display
8797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * the message.
8807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
8817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param context context to get strings.
8827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param mmiCode MMI result.
8837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param previousAlert a previous alert used in this activity.
8847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
8857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static void displayMMIComplete(final Phone phone, Context context, final MmiCode mmiCode,
8867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Message dismissCallbackMessage,
8877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            AlertDialog previousAlert) {
8887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final PhoneGlobals app = PhoneGlobals.getInstance();
8897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        CharSequence text;
8907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        int title = 0;  // title for the progress dialog, if needed.
8917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        MmiCode.State state = mmiCode.getState();
8927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
8937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("displayMMIComplete: state=" + state);
8947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
8957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        switch (state) {
8967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            case PENDING:
8977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // USSD code asking for feedback from user.
8987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                text = mmiCode.getMessage();
8997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (DBG) log("- using text from PENDING MMI message: '" + text + "'");
9007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                break;
9017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            case CANCELLED:
9027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                text = null;
9037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                break;
9047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            case COMPLETE:
9057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (app.getPUKEntryActivity() != null) {
9067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // if an attempt to unPUK the device was made, we specify
9077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // the title and the message here.
9087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    title = com.android.internal.R.string.PinMmi;
9097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    text = context.getText(R.string.puk_unlocked);
9107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    break;
9117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
9127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // All other conditions for the COMPLETE mmi state will cause
9137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // the case to fall through to message logic in common with
9147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // the FAILED case.
9157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
9167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            case FAILED:
9177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                text = mmiCode.getMessage();
9187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (DBG) log("- using text from MMI message: '" + text + "'");
9197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                break;
9207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            default:
9217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                throw new IllegalStateException("Unexpected MmiCode state: " + state);
9227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
9237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
9247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (previousAlert != null) {
9257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            previousAlert.dismiss();
9267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
9277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
9287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Check to see if a UI exists for the PUK activation.  If it does
9297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // exist, then it indicates that we're trying to unblock the PUK.
9307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if ((app.getPUKEntryActivity() != null) && (state == MmiCode.State.COMPLETE)) {
9317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG) log("displaying PUK unblocking progress dialog.");
9327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
9337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // create the progress dialog, make sure the flags and type are
9347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // set correctly.
9357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            ProgressDialog pd = new ProgressDialog(app);
9367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            pd.setTitle(title);
9377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            pd.setMessage(text);
9387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            pd.setCancelable(false);
9397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            pd.setIndeterminate(true);
9407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            pd.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
9417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            pd.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
9427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
9437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // display the dialog
9447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            pd.show();
9457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
9467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // indicate to the Phone app that the progress dialog has
9477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // been assigned for the PUK unlock / SIM READY process.
9487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            app.setPukEntryProgressDialog(pd);
9497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
9507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
9517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // In case of failure to unlock, we'll need to reset the
9527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // PUK unlock activity, so that the user may try again.
9537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (app.getPUKEntryActivity() != null) {
9547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                app.setPukEntryActivity(null);
9557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
9567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
9577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // A USSD in a pending state means that it is still
9587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // interacting with the user.
9597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (state != MmiCode.State.PENDING) {
9607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (DBG) log("MMI code has finished running.");
9617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
9627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (DBG) log("Extended NW displayMMIInitiate (" + text + ")");
9637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (text == null || text.length() == 0)
9647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    return;
9657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
9667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // displaying system alert dialog on the screen instead of
9677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // using another activity to display the message.  This
9687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // places the message at the forefront of the UI.
96937abbab24baec145cdf995693be96cd7162b0c06Etan Cohen
97037abbab24baec145cdf995693be96cd7162b0c06Etan Cohen                if (sUssdDialog == null) {
971e0f2b791135a88de7930e4339686fd5b79e53a9fYorke Lee                    sUssdDialog = new AlertDialog.Builder(context, THEME)
97237abbab24baec145cdf995693be96cd7162b0c06Etan Cohen                            .setPositiveButton(R.string.ok, null)
97337abbab24baec145cdf995693be96cd7162b0c06Etan Cohen                            .setCancelable(true)
97437abbab24baec145cdf995693be96cd7162b0c06Etan Cohen                            .setOnDismissListener(new DialogInterface.OnDismissListener() {
97537abbab24baec145cdf995693be96cd7162b0c06Etan Cohen                                @Override
97637abbab24baec145cdf995693be96cd7162b0c06Etan Cohen                                public void onDismiss(DialogInterface dialog) {
97737abbab24baec145cdf995693be96cd7162b0c06Etan Cohen                                    sUssdMsg.setLength(0);
97837abbab24baec145cdf995693be96cd7162b0c06Etan Cohen                                }
97937abbab24baec145cdf995693be96cd7162b0c06Etan Cohen                            })
98037abbab24baec145cdf995693be96cd7162b0c06Etan Cohen                            .create();
98137abbab24baec145cdf995693be96cd7162b0c06Etan Cohen
98237abbab24baec145cdf995693be96cd7162b0c06Etan Cohen                    sUssdDialog.getWindow().setType(
98337abbab24baec145cdf995693be96cd7162b0c06Etan Cohen                            WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
98437abbab24baec145cdf995693be96cd7162b0c06Etan Cohen                    sUssdDialog.getWindow().addFlags(
98537abbab24baec145cdf995693be96cd7162b0c06Etan Cohen                            WindowManager.LayoutParams.FLAG_DIM_BEHIND);
98637abbab24baec145cdf995693be96cd7162b0c06Etan Cohen                }
98737abbab24baec145cdf995693be96cd7162b0c06Etan Cohen                if (sUssdMsg.length() != 0) {
98837abbab24baec145cdf995693be96cd7162b0c06Etan Cohen                    sUssdMsg
98937abbab24baec145cdf995693be96cd7162b0c06Etan Cohen                            .insert(0, "\n")
99037abbab24baec145cdf995693be96cd7162b0c06Etan Cohen                            .insert(0, app.getResources().getString(R.string.ussd_dialog_sep))
99137abbab24baec145cdf995693be96cd7162b0c06Etan Cohen                            .insert(0, "\n");
99237abbab24baec145cdf995693be96cd7162b0c06Etan Cohen                }
99337abbab24baec145cdf995693be96cd7162b0c06Etan Cohen                sUssdMsg.insert(0, text);
99437abbab24baec145cdf995693be96cd7162b0c06Etan Cohen                sUssdDialog.setMessage(sUssdMsg.toString());
99537abbab24baec145cdf995693be96cd7162b0c06Etan Cohen                sUssdDialog.show();
9967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            } else {
9977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (DBG) log("USSD code has requested user input. Constructing input dialog.");
9987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
9997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // USSD MMI code that is interacting with the user.  The
10007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // basic set of steps is this:
10017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //   1. User enters a USSD request
10027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //   2. We recognize the request and displayMMIInitiate
10037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //      (above) creates a progress dialog.
10047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //   3. Request returns and we get a PENDING or COMPLETE
10057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //      message.
10067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //   4. These MMI messages are caught in the PhoneApp
10077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //      (onMMIComplete) and the InCallScreen
10087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //      (mHandler.handleMessage) which bring up this dialog
10097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //      and closes the original progress dialog,
10107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //      respectively.
10117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //   5. If the message is anything other than PENDING,
10127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //      we are done, and the alert dialog (directly above)
10137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //      displays the outcome.
10147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //   6. If the network is requesting more information from
10157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //      the user, the MMI will be in a PENDING state, and
10167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //      we display this dialog with the message.
10177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //   7. User input, or cancel requests result in a return
10187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //      to step 1.  Keep in mind that this is the only
10197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //      time that a USSD should be canceled.
10207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
10217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // inflate the layout with the scrolling text area for the dialog.
1022b3ee4dc3dd39ebe765ebe6b535b3900bb95813d8Andrew Lee                ContextThemeWrapper contextThemeWrapper =
1023b3ee4dc3dd39ebe765ebe6b535b3900bb95813d8Andrew Lee                        new ContextThemeWrapper(context, R.style.DialerAlertDialogTheme);
1024b3ee4dc3dd39ebe765ebe6b535b3900bb95813d8Andrew Lee                LayoutInflater inflater = (LayoutInflater) contextThemeWrapper.getSystemService(
10257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        Context.LAYOUT_INFLATER_SERVICE);
10267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                View dialogView = inflater.inflate(R.layout.dialog_ussd_response, null);
10277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
10287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // get the input field.
10297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                final EditText inputText = (EditText) dialogView.findViewById(R.id.input_field);
10307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
10317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // specify the dialog's click listener, with SEND and CANCEL logic.
10327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                final DialogInterface.OnClickListener mUSSDDialogListener =
10337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    new DialogInterface.OnClickListener() {
10347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        public void onClick(DialogInterface dialog, int whichButton) {
10357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            switch (whichButton) {
10367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                case DialogInterface.BUTTON_POSITIVE:
10377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                    // As per spec 24.080, valid length of ussd string
10387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                    // is 1 - 160. If length is out of the range then
10397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                    // display toast message & Cancel MMI operation.
10407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                    if (inputText.length() < MIN_USSD_LEN
10417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                            || inputText.length() > MAX_USSD_LEN) {
10427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                        Toast.makeText(app,
10437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                                app.getResources().getString(R.string.enter_input,
10447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                                MIN_USSD_LEN, MAX_USSD_LEN),
10457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                                Toast.LENGTH_LONG).show();
10467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                        if (mmiCode.isCancelable()) {
10477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                            mmiCode.cancel();
10487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                        }
10497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                    } else {
10507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                        phone.sendUssdResponse(inputText.getText().toString());
10517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                    }
10527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                    break;
10537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                case DialogInterface.BUTTON_NEGATIVE:
10547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                    if (mmiCode.isCancelable()) {
10557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                        mmiCode.cancel();
10567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                    }
10577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                    break;
10587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            }
10597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        }
10607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    };
10617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
10627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // build the dialog
1063b3ee4dc3dd39ebe765ebe6b535b3900bb95813d8Andrew Lee                final AlertDialog newDialog = new AlertDialog.Builder(contextThemeWrapper)
10647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        .setMessage(text)
10657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        .setView(dialogView)
10667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        .setPositiveButton(R.string.send_button, mUSSDDialogListener)
10677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        .setNegativeButton(R.string.cancel, mUSSDDialogListener)
10687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        .setCancelable(false)
10697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        .create();
10707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
10717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // attach the key listener to the dialog's input field and make
10727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // sure focus is set.
10737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                final View.OnKeyListener mUSSDDialogInputListener =
10747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    new View.OnKeyListener() {
10757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        public boolean onKey(View v, int keyCode, KeyEvent event) {
10767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            switch (keyCode) {
10777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                case KeyEvent.KEYCODE_CALL:
10787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                case KeyEvent.KEYCODE_ENTER:
10797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                    if(event.getAction() == KeyEvent.ACTION_DOWN) {
10807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                        phone.sendUssdResponse(inputText.getText().toString());
10817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                        newDialog.dismiss();
10827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                    }
10837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                    return true;
10847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            }
10857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            return false;
10867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        }
10877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    };
10887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                inputText.setOnKeyListener(mUSSDDialogInputListener);
10897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                inputText.requestFocus();
10907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
10917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // set the window properties of the dialog
10927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                newDialog.getWindow().setType(
10937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
10947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                newDialog.getWindow().addFlags(
10957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        WindowManager.LayoutParams.FLAG_DIM_BEHIND);
10967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
10977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // now show the dialog!
10987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                newDialog.show();
1099b3ee4dc3dd39ebe765ebe6b535b3900bb95813d8Andrew Lee
1100b3ee4dc3dd39ebe765ebe6b535b3900bb95813d8Andrew Lee                newDialog.getButton(DialogInterface.BUTTON_POSITIVE)
1101b3ee4dc3dd39ebe765ebe6b535b3900bb95813d8Andrew Lee                        .setTextColor(context.getResources().getColor(R.color.dialer_theme_color));
1102b3ee4dc3dd39ebe765ebe6b535b3900bb95813d8Andrew Lee                newDialog.getButton(DialogInterface.BUTTON_NEGATIVE)
1103b3ee4dc3dd39ebe765ebe6b535b3900bb95813d8Andrew Lee                        .setTextColor(context.getResources().getColor(R.color.dialer_theme_color));
11047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
11057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
11067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
11077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
11087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
11097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Cancels the current pending MMI operation, if applicable.
11107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return true if we canceled an MMI operation, or false
11117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *         if the current pending MMI wasn't cancelable
11127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *         or if there was no current pending MMI at all.
11137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
11147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @see displayMMIInitiate
11157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
11167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static boolean cancelMmiCode(Phone phone) {
11177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        List<? extends MmiCode> pendingMmis = phone.getPendingMmiCodes();
11187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        int count = pendingMmis.size();
11197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("cancelMmiCode: num pending MMIs = " + count);
11207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
11217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        boolean canceled = false;
11227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (count > 0) {
11237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // assume that we only have one pending MMI operation active at a time.
11247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // I don't think it's possible to enter multiple MMI codes concurrently
11257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // in the phone UI, because during the MMI operation, an Alert panel
11267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // is displayed, which prevents more MMI code from being entered.
11277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            MmiCode mmiCode = pendingMmis.get(0);
11287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (mmiCode.isCancelable()) {
11297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                mmiCode.cancel();
11307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                canceled = true;
11317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
11327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
11337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return canceled;
11347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
11357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
11367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public static class VoiceMailNumberMissingException extends Exception {
11377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        VoiceMailNumberMissingException() {
11387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            super();
11397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
11407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
11417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        VoiceMailNumberMissingException(String msg) {
11427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            super(msg);
11437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
11447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
11457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
11467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
11477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Given an Intent (which is presumably the ACTION_CALL intent that
11487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * initiated this outgoing call), figure out the actual phone number we
11497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * should dial.
11507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
11517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Note that the returned "number" may actually be a SIP address,
11527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * if the specified intent contains a sip: URI.
11537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
11547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * This method is basically a wrapper around PhoneUtils.getNumberFromIntent(),
11557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * except it's also aware of the EXTRA_ACTUAL_NUMBER_TO_DIAL extra.
11567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * (That extra, if present, tells us the exact string to pass down to the
11577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * telephony layer.  It's guaranteed to be safe to dial: it's either a PSTN
11587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * phone number with separators and keypad letters stripped out, or a raw
11597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * unencoded SIP address.)
11607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
11617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return the phone number corresponding to the specified Intent, or null
11627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *   if the Intent has no action or if the intent's data is malformed or
11637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *   missing.
11647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
11657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @throws VoiceMailNumberMissingException if the intent
11667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *   contains a "voicemail" URI, but there's no voicemail
11677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *   number configured on the device.
11687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
11697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public static String getInitialNumber(Intent intent)
11707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            throws PhoneUtils.VoiceMailNumberMissingException {
11717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("getInitialNumber(): " + intent);
11727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
11737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        String action = intent.getAction();
11747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (TextUtils.isEmpty(action)) {
11757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return null;
11767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
11777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
11787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // If the EXTRA_ACTUAL_NUMBER_TO_DIAL extra is present, get the phone
11797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // number from there.  (That extra takes precedence over the actual data
11807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // included in the intent.)
11817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (intent.hasExtra(OutgoingCallBroadcaster.EXTRA_ACTUAL_NUMBER_TO_DIAL)) {
11827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            String actualNumberToDial =
11837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    intent.getStringExtra(OutgoingCallBroadcaster.EXTRA_ACTUAL_NUMBER_TO_DIAL);
11847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG) {
11857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                log("==> got EXTRA_ACTUAL_NUMBER_TO_DIAL; returning '"
11867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        + toLogSafePhoneNumber(actualNumberToDial) + "'");
11877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
11887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return actualNumberToDial;
11897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
11907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
11917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return getNumberFromIntent(PhoneGlobals.getInstance(), intent);
11927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
11937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
11947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
11957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Gets the phone number to be called from an intent.  Requires a Context
11967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * to access the contacts database, and a Phone to access the voicemail
11977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * number.
11987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
11997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * <p>If <code>phone</code> is <code>null</code>, the function will return
12007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * <code>null</code> for <code>voicemail:</code> URIs;
12017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * if <code>context</code> is <code>null</code>, the function will return
12027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * <code>null</code> for person/phone URIs.</p>
12037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
12047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * <p>If the intent contains a <code>sip:</code> URI, the returned
12057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * "number" is actually the SIP address.
12067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
12077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param context a context to use (or
12087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param intent the intent
12097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
12107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @throws VoiceMailNumberMissingException if <code>intent</code> contains
12117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *         a <code>voicemail:</code> URI, but <code>phone</code> does not
12127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *         have a voicemail number set.
12137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
12147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return the phone number (or SIP address) that would be called by the intent,
12157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *         or <code>null</code> if the number cannot be found.
12167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
12177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static String getNumberFromIntent(Context context, Intent intent)
12187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            throws VoiceMailNumberMissingException {
12197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Uri uri = intent.getData();
12207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        String scheme = uri.getScheme();
12217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
12227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // The sip: scheme is simple: just treat the rest of the URI as a
12237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // SIP address.
1224137458b4bf3516941483e59c123c22cbee27ed43Jay Shrauner        if (PhoneAccount.SCHEME_SIP.equals(scheme)) {
12257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return uri.getSchemeSpecificPart();
12267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
12277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
12287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Otherwise, let PhoneNumberUtils.getNumberFromIntent() handle
12297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // the other cases (i.e. tel: and voicemail: and contact: URIs.)
12307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
12317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final String number = PhoneNumberUtils.getNumberFromIntent(intent, context);
12327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
12337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Check for a voicemail-dialing request.  If the voicemail number is
12347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // empty, throw a VoiceMailNumberMissingException.
1235137458b4bf3516941483e59c123c22cbee27ed43Jay Shrauner        if (PhoneAccount.SCHEME_VOICEMAIL.equals(scheme) &&
12367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                (number == null || TextUtils.isEmpty(number)))
12377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            throw new VoiceMailNumberMissingException();
12387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
12397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return number;
12407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
12417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
12427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
12437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Returns the caller-id info corresponding to the specified Connection.
12447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * (This is just a simple wrapper around CallerInfo.getCallerInfo(): we
12457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * extract a phone number from the specified Connection, and feed that
12467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * number into CallerInfo.getCallerInfo().)
12477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
12487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * The returned CallerInfo may be null in certain error cases, like if the
12497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * specified Connection was null, or if we weren't able to get a valid
12507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * phone number from the Connection.
12517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
12527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Finally, if the getCallerInfo() call did succeed, we save the resulting
12537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * CallerInfo object in the "userData" field of the Connection.
12547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
12557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * NOTE: This API should be avoided, with preference given to the
12567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * asynchronous startGetCallerInfo API.
12577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
12587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static CallerInfo getCallerInfo(Context context, Connection c) {
12597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        CallerInfo info = null;
12607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
12617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (c != null) {
12627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            //See if there is a URI attached.  If there is, this means
12637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            //that there is no CallerInfo queried yet, so we'll need to
12647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            //replace the URI with a full CallerInfo object.
12657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Object userDataObject = c.getUserData();
12667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (userDataObject instanceof Uri) {
12677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                info = CallerInfo.getCallerInfo(context, (Uri) userDataObject);
12687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (info != null) {
12697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    c.setUserData(info);
12707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
12717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            } else {
12727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (userDataObject instanceof CallerInfoToken) {
12737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    //temporary result, while query is running
12747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    info = ((CallerInfoToken) userDataObject).currentInfo;
12757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                } else {
12767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    //final query result
12777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    info = (CallerInfo) userDataObject;
12787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
12797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (info == null) {
12807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // No URI, or Existing CallerInfo, so we'll have to make do with
12817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // querying a new CallerInfo using the connection's phone number.
12827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    String number = c.getAddress();
12837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
12847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    if (DBG) log("getCallerInfo: number = " + toLogSafePhoneNumber(number));
12857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
12867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    if (!TextUtils.isEmpty(number)) {
12877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        info = CallerInfo.getCallerInfo(context, number);
12887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        if (info != null) {
12897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            c.setUserData(info);
12907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        }
12917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    }
12927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
12937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
12947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
12957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return info;
12967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
12977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
12987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
12997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Class returned by the startGetCallerInfo call to package a temporary
13007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * CallerInfo Object, to be superceded by the CallerInfo Object passed
13017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * into the listener when the query with token mAsyncQueryToken is complete.
13027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
13037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public static class CallerInfoToken {
13047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        /**indicates that there will no longer be updates to this request.*/
13057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        public boolean isFinal;
13067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
13077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        public CallerInfo currentInfo;
13087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        public CallerInfoAsyncQuery asyncQuery;
13097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
13107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
13117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
13127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Start a CallerInfo Query based on the earliest connection in the call.
13137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
13147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static CallerInfoToken startGetCallerInfo(Context context, Call call,
13157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            CallerInfoAsyncQuery.OnQueryCompleteListener listener, Object cookie) {
13167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Connection conn = null;
13177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        int phoneType = call.getPhone().getPhoneType();
13187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
13197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            conn = call.getLatestConnection();
13207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else if ((phoneType == PhoneConstants.PHONE_TYPE_GSM)
1321bd76e4e0407f75c4e6a6961cf943d36fc75a0e1aSailesh Nepal                || (phoneType == PhoneConstants.PHONE_TYPE_SIP)
13220ca1c80f1ca60966a16169b109e96ac19fa69743Etan Cohen                || (phoneType == PhoneConstants.PHONE_TYPE_IMS)
1323bd76e4e0407f75c4e6a6961cf943d36fc75a0e1aSailesh Nepal                || (phoneType == PhoneConstants.PHONE_TYPE_THIRD_PARTY)) {
13247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            conn = call.getEarliestConnection();
13257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
13267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            throw new IllegalStateException("Unexpected phone type: " + phoneType);
13277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
13287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
13297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return startGetCallerInfo(context, conn, listener, cookie);
13307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
13317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1332e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng    static CallerInfoToken startGetCallerInfo(Context context, Connection c,
1333e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng            CallerInfoAsyncQuery.OnQueryCompleteListener listener, Object cookie) {
1334e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng        return startGetCallerInfo(context, c, listener, cookie, null);
1335e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng    }
1336e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng
13377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
13387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * place a temporary callerinfo object in the hands of the caller and notify
13397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * caller when the actual query is done.
13407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
13417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static CallerInfoToken startGetCallerInfo(Context context, Connection c,
1342e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng            CallerInfoAsyncQuery.OnQueryCompleteListener listener, Object cookie,
1343e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng            RawGatewayInfo info) {
13447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        CallerInfoToken cit;
13457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
13467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (c == null) {
13477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            //TODO: perhaps throw an exception here.
13487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            cit = new CallerInfoToken();
13497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            cit.asyncQuery = null;
13507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return cit;
13517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
13527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
13537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Object userDataObject = c.getUserData();
13547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
13557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // There are now 3 states for the Connection's userData object:
13567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //
13577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //   (1) Uri - query has not been executed yet
13587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //
13597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //   (2) CallerInfoToken - query is executing, but has not completed.
13607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //
13617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //   (3) CallerInfo - query has executed.
13627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //
13637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // In each case we have slightly different behaviour:
13647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //   1. If the query has not been executed yet (Uri or null), we start
13657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      query execution asynchronously, and note it by attaching a
13667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      CallerInfoToken as the userData.
13677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //   2. If the query is executing (CallerInfoToken), we've essentially
13687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      reached a state where we've received multiple requests for the
13697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      same callerInfo.  That means that once the query is complete,
13707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      we'll need to execute the additional listener requested.
13717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //   3. If the query has already been executed (CallerInfo), we just
13727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      return the CallerInfo object as expected.
13737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //   4. Regarding isFinal - there are cases where the CallerInfo object
13747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      will not be attached, like when the number is empty (caller id
13757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      blocking).  This flag is used to indicate that the
13767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      CallerInfoToken object is going to be permanent since no
13777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      query results will be returned.  In the case where a query
13787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      has been completed, this flag is used to indicate to the caller
13797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      that the data will not be updated since it is valid.
13807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //
13817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      Note: For the case where a number is NOT retrievable, we leave
13827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      the CallerInfo as null in the CallerInfoToken.  This is
13837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      something of a departure from the original code, since the old
13847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      code manufactured a CallerInfo object regardless of the query
13857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      outcome.  From now on, we will append an empty CallerInfo
13867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      object, to mirror previous behaviour, and to avoid Null Pointer
13877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //      Exceptions.
13887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
13897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (userDataObject instanceof Uri) {
13907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // State (1): query has not been executed yet
13917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
13927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            //create a dummy callerinfo, populate with what we know from URI.
13937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            cit = new CallerInfoToken();
13947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            cit.currentInfo = new CallerInfo();
13957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            cit.asyncQuery = CallerInfoAsyncQuery.startQuery(QUERY_TOKEN, context,
13967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    (Uri) userDataObject, sCallerInfoQueryListener, c);
13977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            cit.asyncQuery.addQueryListener(QUERY_TOKEN, listener, cookie);
13987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            cit.isFinal = false;
13997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
14007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            c.setUserData(cit);
14017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
14027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG) log("startGetCallerInfo: query based on Uri: " + userDataObject);
14037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
14047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else if (userDataObject == null) {
14057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // No URI, or Existing CallerInfo, so we'll have to make do with
14067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // querying a new CallerInfo using the connection's phone number.
14077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            String number = c.getAddress();
14087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1409685dcb6b0268af57ac5b93a2e5b259eb519fa2d8Chiao Cheng            if (info != null && info != CallGatewayManager.EMPTY_INFO) {
1410e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng                // Gateway number, the connection number is actually the gateway number.
1411e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng                // need to lookup via dialed number.
1412e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng                number = info.trueNumber;
1413e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng            }
1414e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng
14157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG) {
14167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                log("PhoneUtils.startGetCallerInfo: new query for phone number...");
14177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                log("- number (address): " + toLogSafePhoneNumber(number));
14187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                log("- c: " + c);
14197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                log("- phone: " + c.getCall().getPhone());
14207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                int phoneType = c.getCall().getPhone().getPhoneType();
14217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                log("- phoneType: " + phoneType);
14227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                switch (phoneType) {
14237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    case PhoneConstants.PHONE_TYPE_NONE: log("  ==> PHONE_TYPE_NONE"); break;
14247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    case PhoneConstants.PHONE_TYPE_GSM: log("  ==> PHONE_TYPE_GSM"); break;
14250ca1c80f1ca60966a16169b109e96ac19fa69743Etan Cohen                    case PhoneConstants.PHONE_TYPE_IMS: log("  ==> PHONE_TYPE_IMS"); break;
14267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    case PhoneConstants.PHONE_TYPE_CDMA: log("  ==> PHONE_TYPE_CDMA"); break;
14277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    case PhoneConstants.PHONE_TYPE_SIP: log("  ==> PHONE_TYPE_SIP"); break;
1428bd76e4e0407f75c4e6a6961cf943d36fc75a0e1aSailesh Nepal                    case PhoneConstants.PHONE_TYPE_THIRD_PARTY:
1429bd76e4e0407f75c4e6a6961cf943d36fc75a0e1aSailesh Nepal                        log("  ==> PHONE_TYPE_THIRD_PARTY");
1430bd76e4e0407f75c4e6a6961cf943d36fc75a0e1aSailesh Nepal                        break;
14317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    default: log("  ==> Unknown phone type"); break;
14327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
14337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
14347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
14357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            cit = new CallerInfoToken();
14367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            cit.currentInfo = new CallerInfo();
14377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
14387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // Store CNAP information retrieved from the Connection (we want to do this
14397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // here regardless of whether the number is empty or not).
14407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            cit.currentInfo.cnapName =  c.getCnapName();
14417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            cit.currentInfo.name = cit.currentInfo.cnapName; // This can still get overwritten
14427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                                             // by ContactInfo later
14437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            cit.currentInfo.numberPresentation = c.getNumberPresentation();
14447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            cit.currentInfo.namePresentation = c.getCnapNamePresentation();
14457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
14467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (VDBG) {
14477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                log("startGetCallerInfo: number = " + number);
14487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                log("startGetCallerInfo: CNAP Info from FW(1): name="
14497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    + cit.currentInfo.cnapName
14507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    + ", Name/Number Pres=" + cit.currentInfo.numberPresentation);
14517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
14527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
14537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // handling case where number is null (caller id hidden) as well.
14547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (!TextUtils.isEmpty(number)) {
14557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // Check for special CNAP cases and modify the CallerInfo accordingly
14567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // to be sure we keep the right information to display/log later
14577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                number = modifyForSpecialCnapCases(context, cit.currentInfo, number,
14587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        cit.currentInfo.numberPresentation);
14597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
14607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                cit.currentInfo.phoneNumber = number;
14617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // For scenarios where we may receive a valid number from the network but a
14627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // restricted/unavailable presentation, we do not want to perform a contact query
14637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // (see note on isFinal above). So we set isFinal to true here as well.
14647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (cit.currentInfo.numberPresentation != PhoneConstants.PRESENTATION_ALLOWED) {
14657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    cit.isFinal = true;
14667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                } else {
14677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    if (DBG) log("==> Actually starting CallerInfoAsyncQuery.startQuery()...");
14687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    cit.asyncQuery = CallerInfoAsyncQuery.startQuery(QUERY_TOKEN, context,
14697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            number, sCallerInfoQueryListener, c);
14707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    cit.asyncQuery.addQueryListener(QUERY_TOKEN, listener, cookie);
14717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    cit.isFinal = false;
14727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
14737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            } else {
14747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // This is the case where we are querying on a number that
14757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // is null or empty, like a caller whose caller id is
14767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // blocked or empty (CLIR).  The previous behaviour was to
14777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // throw a null CallerInfo object back to the user, but
14787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // this departure is somewhat cleaner.
14797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (DBG) log("startGetCallerInfo: No query to start, send trivial reply.");
14807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                cit.isFinal = true; // please see note on isFinal, above.
14817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
14827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
14837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            c.setUserData(cit);
14847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
14857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG) {
14867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                log("startGetCallerInfo: query based on number: " + toLogSafePhoneNumber(number));
14877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
14887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
14897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else if (userDataObject instanceof CallerInfoToken) {
14907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // State (2): query is executing, but has not completed.
14917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
14927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // just tack on this listener to the queue.
14937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            cit = (CallerInfoToken) userDataObject;
14947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
14957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // handling case where number is null (caller id hidden) as well.
14967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (cit.asyncQuery != null) {
14977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                cit.asyncQuery.addQueryListener(QUERY_TOKEN, listener, cookie);
14987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
14997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (DBG) log("startGetCallerInfo: query already running, adding listener: " +
15007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        listener.getClass().toString());
15017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            } else {
15027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // handling case where number/name gets updated later on by the network
15037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                String updatedNumber = c.getAddress();
1504e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng
1505e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng                if (info != null) {
1506e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng                    // Gateway number, the connection number is actually the gateway number.
1507e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng                    // need to lookup via dialed number.
1508e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng                    updatedNumber = info.trueNumber;
1509e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng                }
1510e365ba74f63afea89e789f5b94187ee83ee80c8cChiao Cheng
15117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (DBG) {
15127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    log("startGetCallerInfo: updatedNumber initially = "
15137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            + toLogSafePhoneNumber(updatedNumber));
15147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
15157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (!TextUtils.isEmpty(updatedNumber)) {
15167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // Store CNAP information retrieved from the Connection
15177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    cit.currentInfo.cnapName =  c.getCnapName();
15187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // This can still get overwritten by ContactInfo
15197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    cit.currentInfo.name = cit.currentInfo.cnapName;
15207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    cit.currentInfo.numberPresentation = c.getNumberPresentation();
15217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    cit.currentInfo.namePresentation = c.getCnapNamePresentation();
15227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
15237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    updatedNumber = modifyForSpecialCnapCases(context, cit.currentInfo,
15247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            updatedNumber, cit.currentInfo.numberPresentation);
15257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
15267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    cit.currentInfo.phoneNumber = updatedNumber;
15277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    if (DBG) {
15287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        log("startGetCallerInfo: updatedNumber="
15297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                + toLogSafePhoneNumber(updatedNumber));
15307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    }
15317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    if (VDBG) {
15327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        log("startGetCallerInfo: CNAP Info from FW(2): name="
15337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                + cit.currentInfo.cnapName
15347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                + ", Name/Number Pres=" + cit.currentInfo.numberPresentation);
15357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    } else if (DBG) {
15367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        log("startGetCallerInfo: CNAP Info from FW(2)");
15377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    }
15387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // For scenarios where we may receive a valid number from the network but a
15397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // restricted/unavailable presentation, we do not want to perform a contact query
15407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // (see note on isFinal above). So we set isFinal to true here as well.
15417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    if (cit.currentInfo.numberPresentation != PhoneConstants.PRESENTATION_ALLOWED) {
15427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        cit.isFinal = true;
15437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    } else {
15447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        cit.asyncQuery = CallerInfoAsyncQuery.startQuery(QUERY_TOKEN, context,
15457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                updatedNumber, sCallerInfoQueryListener, c);
15467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        cit.asyncQuery.addQueryListener(QUERY_TOKEN, listener, cookie);
15477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        cit.isFinal = false;
15487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    }
15497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                } else {
15507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    if (DBG) log("startGetCallerInfo: No query to attach to, send trivial reply.");
15517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    if (cit.currentInfo == null) {
15527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        cit.currentInfo = new CallerInfo();
15537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    }
15547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // Store CNAP information retrieved from the Connection
15557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    cit.currentInfo.cnapName = c.getCnapName();  // This can still get
15567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                                                 // overwritten by ContactInfo
15577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    cit.currentInfo.name = cit.currentInfo.cnapName;
15587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    cit.currentInfo.numberPresentation = c.getNumberPresentation();
15597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    cit.currentInfo.namePresentation = c.getCnapNamePresentation();
15607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
15617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    if (VDBG) {
15627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        log("startGetCallerInfo: CNAP Info from FW(3): name="
15637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                + cit.currentInfo.cnapName
15647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                + ", Name/Number Pres=" + cit.currentInfo.numberPresentation);
15657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    } else if (DBG) {
15667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        log("startGetCallerInfo: CNAP Info from FW(3)");
15677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    }
15687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    cit.isFinal = true; // please see note on isFinal, above.
15697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
15707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
15717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
15727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // State (3): query is complete.
15737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
15747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // The connection's userDataObject is a full-fledged
15757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // CallerInfo instance.  Wrap it in a CallerInfoToken and
15767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // return it to the user.
15777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
15787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            cit = new CallerInfoToken();
15797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            cit.currentInfo = (CallerInfo) userDataObject;
15807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            cit.asyncQuery = null;
15817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            cit.isFinal = true;
15827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // since the query is already done, call the listener.
15837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG) log("startGetCallerInfo: query already done, returning CallerInfo");
15847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG) log("==> cit.currentInfo = " + cit.currentInfo);
15857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
15867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return cit;
15877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
15887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
15897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
15907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Static CallerInfoAsyncQuery.OnQueryCompleteListener instance that
15917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * we use with all our CallerInfoAsyncQuery.startQuery() requests.
15927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
15937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static final int QUERY_TOKEN = -1;
15947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static CallerInfoAsyncQuery.OnQueryCompleteListener sCallerInfoQueryListener =
15957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        new CallerInfoAsyncQuery.OnQueryCompleteListener () {
15967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            /**
15977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon             * When the query completes, we stash the resulting CallerInfo
15987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon             * object away in the Connection's "userData" (where it will
15997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon             * later be retrieved by the in-call UI.)
16007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon             */
16017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            public void onQueryComplete(int token, Object cookie, CallerInfo ci) {
16027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (DBG) log("query complete, updating connection.userdata");
16037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Connection conn = (Connection) cookie;
16047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
16057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // Added a check if CallerInfo is coming from ContactInfo or from Connection.
16067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // If no ContactInfo, then we want to use CNAP information coming from network
16077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (DBG) log("- onQueryComplete: CallerInfo:" + ci);
16087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (ci.contactExists || ci.isEmergencyNumber() || ci.isVoiceMailNumber()) {
16097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // If the number presentation has not been set by
16107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // the ContactInfo, use the one from the
16117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // connection.
16127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
16137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // TODO: Need a new util method to merge the info
16147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // from the Connection in a CallerInfo object.
16157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // Here 'ci' is a new CallerInfo instance read
16167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // from the DB. It has lost all the connection
16177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // info preset before the query (see PhoneUtils
16187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // line 1334). We should have a method to merge
16197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // back into this new instance the info from the
16207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // connection object not set by the DB. If the
16217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // Connection already has a CallerInfo instance in
16227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // userData, then we could use this instance to
16237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // fill 'ci' in. The same routine could be used in
16247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // PhoneUtils.
16257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    if (0 == ci.numberPresentation) {
16267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        ci.numberPresentation = conn.getNumberPresentation();
16277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    }
16287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                } else {
16297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // No matching contact was found for this number.
16307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // Return a new CallerInfo based solely on the CNAP
16317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // information from the network.
16327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
16337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    CallerInfo newCi = getCallerInfo(null, conn);
16347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
16357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // ...but copy over the (few) things we care about
16367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // from the original CallerInfo object:
16377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    if (newCi != null) {
16387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        newCi.phoneNumber = ci.phoneNumber; // To get formatted phone number
16397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        newCi.geoDescription = ci.geoDescription; // To get geo description string
16407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        ci = newCi;
16417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    }
16427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
16437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
16447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (DBG) log("==> Stashing CallerInfo " + ci + " into the connection...");
16457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                conn.setUserData(ci);
16467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
16477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        };
16487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
16497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
16507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
16517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Returns a single "name" for the specified given a CallerInfo object.
16527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * If the name is null, return defaultString as the default value, usually
16537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * context.getString(R.string.unknown).
16547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
16557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static String getCompactNameFromCallerInfo(CallerInfo ci, Context context) {
16567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("getCompactNameFromCallerInfo: info = " + ci);
16577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
16587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        String compactName = null;
16597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (ci != null) {
16607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (TextUtils.isEmpty(ci.name)) {
16617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // Perform any modifications for special CNAP cases to
16627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // the phone number being displayed, if applicable.
16637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                compactName = modifyForSpecialCnapCases(context, ci, ci.phoneNumber,
16647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                                        ci.numberPresentation);
16657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            } else {
16667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // Don't call modifyForSpecialCnapCases on regular name. See b/2160795.
16677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                compactName = ci.name;
16687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
16697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
16707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
16717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if ((compactName == null) || (TextUtils.isEmpty(compactName))) {
16727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // If we're still null/empty here, then check if we have a presentation
16737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // string that takes precedence that we could return, otherwise display
16747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // "unknown" string.
16757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (ci != null && ci.numberPresentation == PhoneConstants.PRESENTATION_RESTRICTED) {
16767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                compactName = context.getString(R.string.private_num);
16777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            } else if (ci != null && ci.numberPresentation == PhoneConstants.PRESENTATION_PAYPHONE) {
16787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                compactName = context.getString(R.string.payphone);
16797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            } else {
16807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                compactName = context.getString(R.string.unknown);
16817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
16827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
16837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (VDBG) log("getCompactNameFromCallerInfo: compactName=" + compactName);
16847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return compactName;
16857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
16867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
16877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
16887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Returns true if the specified Call is a "conference call", meaning
16897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * that it owns more than one Connection object.  This information is
16907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * used to trigger certain UI changes that appear when a conference
16917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * call is active (like displaying the label "Conference call", and
16927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * enabling the "Manage conference" UI.)
16937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
16947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Watch out: This method simply checks the number of Connections,
16957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * *not* their states.  So if a Call has (for example) one ACTIVE
16967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * connection and one DISCONNECTED connection, this method will return
16977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * true (which is unintuitive, since the Call isn't *really* a
16987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * conference call any more.)
16997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
17007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return true if the specified call has more than one connection (in any state.)
17017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
17027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static boolean isConferenceCall(Call call) {
17037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // CDMA phones don't have the same concept of "conference call" as
17047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // GSM phones do; there's no special "conference call" state of
17057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // the UI or a "manage conference" function.  (Instead, when
17067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // you're in a 3-way call, all we can do is display the "generic"
17077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // state of the UI.)  So as far as the in-call UI is concerned,
17087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Conference corresponds to generic display.
17097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final PhoneGlobals app = PhoneGlobals.getInstance();
17107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        int phoneType = call.getPhone().getPhoneType();
17117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
17127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            CdmaPhoneCallState.PhoneCallState state = app.cdmaPhoneCallState.getCurrentCallState();
17137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if ((state == CdmaPhoneCallState.PhoneCallState.CONF_CALL)
17147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    || ((state == CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE)
17157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    && !app.cdmaPhoneCallState.IsThreeWayCallOrigStateDialing())) {
17167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                return true;
17177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
17187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
17197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            List<Connection> connections = call.getConnections();
17207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (connections != null && connections.size() > 1) {
17217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                return true;
17227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
17237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
17247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return false;
17257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
17267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // TODO: We may still want to change the semantics of this method
17277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // to say that a given call is only really a conference call if
17287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // the number of ACTIVE connections, not the total number of
17297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // connections, is greater than one.  (See warning comment in the
17307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // javadoc above.)
17317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Here's an implementation of that:
17327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //        if (connections == null) {
17337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //            return false;
17347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //        }
17357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //        int numActiveConnections = 0;
17367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //        for (Connection conn : connections) {
17377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //            if (DBG) log("  - CONN: " + conn + ", state = " + conn.getState());
17387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //            if (conn.getState() == Call.State.ACTIVE) numActiveConnections++;
17397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //            if (numActiveConnections > 1) {
17407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //                return true;
17417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //            }
17427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //        }
17437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //        return false;
17447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
17457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
17467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
17477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Launch the Dialer to start a new call.
17487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * This is just a wrapper around the ACTION_DIAL intent.
17497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
17507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /* package */ static boolean startNewCall(final CallManager cm) {
17517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final PhoneGlobals app = PhoneGlobals.getInstance();
17527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
17537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Sanity-check that this is OK given the current state of the phone.
17547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (!okToAddCall(cm)) {
17557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Log.w(LOG_TAG, "startNewCall: can't add a new call in the current state");
17567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            dumpCallManager();
17577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return false;
17587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
17597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
17607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Intent intent = new Intent(Intent.ACTION_DIAL);
17617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
17627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
17637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // when we request the dialer come up, we also want to inform
17647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // it that we're going through the "add call" option from the
17657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // InCallScreen / PhoneUtils.
17667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        intent.putExtra(ADD_CALL_MODE_KEY, true);
17677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        try {
17687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            app.startActivity(intent);
17697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } catch (ActivityNotFoundException e) {
17707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // This is rather rare but possible.
17717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // Note: this method is used even when the phone is encrypted. At that moment
17727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // the system may not find any Activity which can accept this Intent.
17737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Log.e(LOG_TAG, "Activity for adding calls isn't found.");
17747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return false;
17757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
17767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
17777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return true;
17787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
17797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
17807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
17817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Turns on/off speaker.
17827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
17837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param context Context
17847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param flag True when speaker should be on. False otherwise.
17857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param store True when the settings should be stored in the device.
17867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
17877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /* package */ static void turnOnSpeaker(Context context, boolean flag, boolean store) {
17887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("turnOnSpeaker(flag=" + flag + ", store=" + store + ")...");
17897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final PhoneGlobals app = PhoneGlobals.getInstance();
17907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
17917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
17927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        audioManager.setSpeakerphoneOn(flag);
17937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
17947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // record the speaker-enable value
17957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (store) {
17967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            sIsSpeakerEnabled = flag;
17977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
17987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
17997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // We also need to make a fresh call to PhoneApp.updateWakeState()
18007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // any time the speaker state changes, since the screen timeout is
18017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // sometimes different depending on whether or not the speaker is
18027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // in use.
18037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        app.updateWakeState();
18047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1805eee6a9e11d50f918b278dad2133cc6408e27369dHariprasad Jayakumar        app.mCM.setEchoSuppressionEnabled();
18067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
18077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
18087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
18097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Restore the speaker mode, called after a wired headset disconnect
18107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * event.
18117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
18127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static void restoreSpeakerMode(Context context) {
18137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("restoreSpeakerMode, restoring to: " + sIsSpeakerEnabled);
18147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
18157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // change the mode if needed.
18167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (isSpeakerOn(context) != sIsSpeakerEnabled) {
18177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            turnOnSpeaker(context, sIsSpeakerEnabled, false);
18187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
18197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
18207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
18217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static boolean isSpeakerOn(Context context) {
18227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
18237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return audioManager.isSpeakerphoneOn();
18247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
18257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
18267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
18277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static void turnOnNoiseSuppression(Context context, boolean flag, boolean store) {
18287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("turnOnNoiseSuppression: " + flag);
18297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
18307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
18317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (!context.getResources().getBoolean(R.bool.has_in_call_noise_suppression)) {
18327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return;
18337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
18347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
18357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (flag) {
18367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            audioManager.setParameters("noise_suppression=auto");
18377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
18387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            audioManager.setParameters("noise_suppression=off");
18397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
18407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
18417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // record the speaker-enable value
18427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (store) {
18437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            sIsNoiseSuppressionEnabled = flag;
18447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
18457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
18467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // TODO: implement and manage ICON
18477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
18487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
18497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
18507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static void restoreNoiseSuppression(Context context) {
18517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("restoreNoiseSuppression, restoring to: " + sIsNoiseSuppressionEnabled);
18527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
18537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (!context.getResources().getBoolean(R.bool.has_in_call_noise_suppression)) {
18547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return;
18557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
18567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
18577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // change the mode if needed.
18587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (isNoiseSuppressionOn(context) != sIsNoiseSuppressionEnabled) {
18597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            turnOnNoiseSuppression(context, sIsNoiseSuppressionEnabled, false);
18607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
18617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
18627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
18637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static boolean isNoiseSuppressionOn(Context context) {
18647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
18657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (!context.getResources().getBoolean(R.bool.has_in_call_noise_suppression)) {
18667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return false;
18677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
18687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
18697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
18707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        String noiseSuppression = audioManager.getParameters("noise_suppression");
18717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("isNoiseSuppressionOn: " + noiseSuppression);
18727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (noiseSuppression.contains("off")) {
18737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return false;
18747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
18757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return true;
18767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
18777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
18787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1879c264cba0b6ea81b3f741d9c41a0a50b7ffd19220Santos Cordon    static boolean isInEmergencyCall(CallManager cm) {
1880c264cba0b6ea81b3f741d9c41a0a50b7ffd19220Santos Cordon        for (Connection cn : cm.getActiveFgCall().getConnections()) {
188136bb2546cbc86a4e6d338c3c31bbd02c4602b5e2Yorke Lee            if (PhoneNumberUtils.isLocalEmergencyNumber(PhoneGlobals.getInstance(),
188236bb2546cbc86a4e6d338c3c31bbd02c4602b5e2Yorke Lee                    cn.getAddress())) {
1883c264cba0b6ea81b3f741d9c41a0a50b7ffd19220Santos Cordon                return true;
1884c264cba0b6ea81b3f741d9c41a0a50b7ffd19220Santos Cordon            }
1885c264cba0b6ea81b3f741d9c41a0a50b7ffd19220Santos Cordon        }
1886c264cba0b6ea81b3f741d9c41a0a50b7ffd19220Santos Cordon        return false;
1887c264cba0b6ea81b3f741d9c41a0a50b7ffd19220Santos Cordon    }
1888c264cba0b6ea81b3f741d9c41a0a50b7ffd19220Santos Cordon
18897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
18907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Get the mute state of foreground phone, which has the current
18917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * foreground call
18927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
18937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static boolean getMute() {
1894bb2bcef62b916b1b544195ca671d56af6ed32cc2Santos Cordon        return false;
18957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
18967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
18977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /* package */ static void setAudioMode() {
18987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
18997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
19007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
19017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Sets the audio mode per current phone state.
19027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
19037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /* package */ static void setAudioMode(CallManager cm) {
19047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
19057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
19067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
19077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Look for ANY connections on the phone that qualify as being
19087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * disconnected.
19097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
19107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return true if we find a connection that is disconnected over
19117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * all the phone's call objects.
19127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
19137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /* package */ static boolean hasDisconnectedConnections(Phone phone) {
19147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return hasDisconnectedConnections(phone.getForegroundCall()) ||
19157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                hasDisconnectedConnections(phone.getBackgroundCall()) ||
19167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                hasDisconnectedConnections(phone.getRingingCall());
19177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
19187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
19197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
19207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Iterate over all connections in a call to see if there are any
19217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * that are not alive (disconnected or idle).
19227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
19237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return true if we find a connection that is disconnected, and
19247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * pending removal via
19257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * {@link com.android.internal.telephony.gsm.GsmCall#clearDisconnected()}.
19267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
19277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static final boolean hasDisconnectedConnections(Call call) {
19287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // look through all connections for non-active ones.
19297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        for (Connection c : call.getConnections()) {
19307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (!c.isAlive()) {
19317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                return true;
19327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
19337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
19347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return false;
19357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
19367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
19377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    //
19387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    // Misc UI policy helper functions
19397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    //
19407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
19417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
1942af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen     * @return true if we're allowed to hold calls, given the current
1943af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen     * state of the Phone.
1944af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen     */
1945af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen    /* package */ static boolean okToHoldCall(CallManager cm) {
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        // The "Hold" control is disabled entirely if there's
1951af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen        // no way to either hold or unhold in the current state.
1952af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen        final boolean okToHold = (fgCallState == Call.State.ACTIVE) && !hasHoldingCall;
1953af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen        final boolean okToUnhold = cm.hasActiveBgCall() && (fgCallState == Call.State.IDLE);
1954af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen        final boolean canHold = okToHold || okToUnhold;
1955af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen
1956af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen        return canHold;
1957af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen    }
1958af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen
1959af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen    /**
1960af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen     * @return true if we support holding calls, given the current
1961af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen     * state of the Phone.
1962af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen     */
1963af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen    /* package */ static boolean okToSupportHold(CallManager cm) {
1964af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen        boolean supportsHold = false;
1965af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen
1966af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen        final Call fgCall = cm.getActiveFgCall();
1967af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen        final boolean hasHoldingCall = cm.hasActiveBgCall();
1968af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen        final Call.State fgCallState = fgCall.getState();
1969af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen
1970af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen        if (TelephonyCapabilities.supportsHoldAndUnhold(fgCall.getPhone())) {
1971af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen            // This phone has the concept of explicit "Hold" and "Unhold" actions.
1972af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen            supportsHold = true;
1973af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen        } else if (hasHoldingCall && (fgCallState == Call.State.IDLE)) {
1974af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen            // Even when foreground phone device doesn't support hold/unhold, phone devices
1975af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen            // for background holding calls may do.
1976af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen            final Call bgCall = cm.getFirstActiveBgCall();
1977af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen            if (bgCall != null &&
1978af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen                    TelephonyCapabilities.supportsHoldAndUnhold(bgCall.getPhone())) {
1979af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen                supportsHold = true;
1980af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen            }
1981af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen        }
1982af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen        return supportsHold;
1983af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen    }
1984af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen
1985af2fd0ad9669ce110dfcf13bb7bf996e8a387a91Christine Chen    /**
19867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return true if we're allowed to swap calls, given the current
19877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * state of the Phone.
19887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
19897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /* package */ static boolean okToSwapCalls(CallManager cm) {
19907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        int phoneType = cm.getDefaultPhone().getPhoneType();
19917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
19927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // CDMA: "Swap" is enabled only when the phone reaches a *generic*.
19937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // state by either accepting a Call Waiting or by merging two calls
19947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            PhoneGlobals app = PhoneGlobals.getInstance();
19957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return (app.cdmaPhoneCallState.getCurrentCallState()
19967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    == CdmaPhoneCallState.PhoneCallState.CONF_CALL);
19977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else if ((phoneType == PhoneConstants.PHONE_TYPE_GSM)
1998bd76e4e0407f75c4e6a6961cf943d36fc75a0e1aSailesh Nepal                || (phoneType == PhoneConstants.PHONE_TYPE_SIP)
19990ca1c80f1ca60966a16169b109e96ac19fa69743Etan Cohen                || (phoneType == PhoneConstants.PHONE_TYPE_IMS)
2000bd76e4e0407f75c4e6a6961cf943d36fc75a0e1aSailesh Nepal                || (phoneType == PhoneConstants.PHONE_TYPE_THIRD_PARTY)) {
20017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // GSM: "Swap" is available if both lines are in use and there's no
20027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // incoming call.  (Actually we need to verify that the active
20037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // call really is in the ACTIVE state and the holding call really
20047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // is in the HOLDING state, since you *can't* actually swap calls
20057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // when the foreground call is DIALING or ALERTING.)
20067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return !cm.hasActiveRingingCall()
20077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    && (cm.getActiveFgCall().getState() == Call.State.ACTIVE)
20087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    && (cm.getFirstActiveBgCall().getState() == Call.State.HOLDING);
20097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
20107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            throw new IllegalStateException("Unexpected phone type: " + phoneType);
20117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
20127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
20137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
20147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
20157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return true if we're allowed to merge calls, given the current
20167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * state of the Phone.
20177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
20187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /* package */ static boolean okToMergeCalls(CallManager cm) {
20197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        int phoneType = cm.getFgPhone().getPhoneType();
20207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
20217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // CDMA: "Merge" is enabled only when the user is in a 3Way call.
20227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            PhoneGlobals app = PhoneGlobals.getInstance();
20237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return ((app.cdmaPhoneCallState.getCurrentCallState()
20247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    == CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE)
20257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    && !app.cdmaPhoneCallState.IsThreeWayCallOrigStateDialing());
20267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
20277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // GSM: "Merge" is available if both lines are in use and there's no
20287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // incoming call, *and* the current conference isn't already
20297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // "full".
20307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // TODO: shall move all okToMerge logic to CallManager
20317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return !cm.hasActiveRingingCall() && cm.hasActiveFgCall()
20327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    && cm.hasActiveBgCall()
20337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    && cm.canConference(cm.getFirstActiveBgCall());
20347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
20357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
20367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
20377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
20387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return true if the UI should let you add a new call, given the current
20397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * state of the Phone.
20407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
20417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /* package */ static boolean okToAddCall(CallManager cm) {
20427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Phone phone = cm.getActiveFgCall().getPhone();
20437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
20447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // "Add call" is never allowed in emergency callback mode (ECM).
20457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (isPhoneInEcm(phone)) {
20467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return false;
20477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
20487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
20497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        int phoneType = phone.getPhoneType();
20507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final Call.State fgCallState = cm.getActiveFgCall().getState();
20517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
20527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon           // CDMA: "Add call" button is only enabled when:
20537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon           // - ForegroundCall is in ACTIVE state
20547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon           // - After 30 seconds of user Ignoring/Missing a Call Waiting call.
20557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            PhoneGlobals app = PhoneGlobals.getInstance();
20567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return ((fgCallState == Call.State.ACTIVE)
20577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    && (app.cdmaPhoneCallState.getAddCallMenuStateAfterCallWaiting()));
20587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else if ((phoneType == PhoneConstants.PHONE_TYPE_GSM)
2059bd76e4e0407f75c4e6a6961cf943d36fc75a0e1aSailesh Nepal                || (phoneType == PhoneConstants.PHONE_TYPE_SIP)
20600ca1c80f1ca60966a16169b109e96ac19fa69743Etan Cohen                || (phoneType == PhoneConstants.PHONE_TYPE_IMS)
2061bd76e4e0407f75c4e6a6961cf943d36fc75a0e1aSailesh Nepal                || (phoneType == PhoneConstants.PHONE_TYPE_THIRD_PARTY)) {
20627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // GSM: "Add call" is available only if ALL of the following are true:
20637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // - There's no incoming ringing call
20647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // - There's < 2 lines in use
20657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // - The foreground call is ACTIVE or IDLE or DISCONNECTED.
20667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            //   (We mainly need to make sure it *isn't* DIALING or ALERTING.)
20677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            final boolean hasRingingCall = cm.hasActiveRingingCall();
20687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            final boolean hasActiveCall = cm.hasActiveFgCall();
20697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            final boolean hasHoldingCall = cm.hasActiveBgCall();
20707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            final boolean allLinesTaken = hasActiveCall && hasHoldingCall;
20717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
20727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return !hasRingingCall
20737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    && !allLinesTaken
20747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    && ((fgCallState == Call.State.ACTIVE)
20757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        || (fgCallState == Call.State.IDLE)
20767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        || (fgCallState == Call.State.DISCONNECTED));
20777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
20787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            throw new IllegalStateException("Unexpected phone type: " + phoneType);
20797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
20807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
20817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
20827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
20837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Based on the input CNAP number string,
20847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return _RESTRICTED or _UNKNOWN for all the special CNAP strings.
20857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Otherwise, return CNAP_SPECIAL_CASE_NO.
20867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
20877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static int checkCnapSpecialCases(String n) {
20887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (n.equals("PRIVATE") ||
20897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                n.equals("P") ||
20907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                n.equals("RES")) {
20917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG) log("checkCnapSpecialCases, PRIVATE string: " + n);
20927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return PhoneConstants.PRESENTATION_RESTRICTED;
20937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else if (n.equals("UNAVAILABLE") ||
20947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                n.equals("UNKNOWN") ||
20957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                n.equals("UNA") ||
20967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                n.equals("U")) {
20977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG) log("checkCnapSpecialCases, UNKNOWN string: " + n);
20987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return PhoneConstants.PRESENTATION_UNKNOWN;
20997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
21007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG) log("checkCnapSpecialCases, normal str. number: " + n);
21017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return CNAP_SPECIAL_CASE_NO;
21027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
21037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
21047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
21057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
21067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Handles certain "corner cases" for CNAP. When we receive weird phone numbers
21077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * from the network to indicate different number presentations, convert them to
21087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * expected number and presentation values within the CallerInfo object.
21097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param number number we use to verify if we are in a corner case
21107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param presentation presentation value used to verify if we are in a corner case
21117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return the new String that should be used for the phone number
21127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
21137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /* package */ static String modifyForSpecialCnapCases(Context context, CallerInfo ci,
21147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            String number, int presentation) {
21157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Obviously we return number if ci == null, but still return number if
21167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // number == null, because in these cases the correct string will still be
21177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // displayed/logged after this function returns based on the presentation value.
21187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (ci == null || number == null) return number;
21197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
21207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) {
21217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            log("modifyForSpecialCnapCases: initially, number="
21227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    + toLogSafePhoneNumber(number)
21237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    + ", presentation=" + presentation + " ci " + ci);
21247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
21257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
21267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // "ABSENT NUMBER" is a possible value we could get from the network as the
21277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // phone number, so if this happens, change it to "Unknown" in the CallerInfo
21287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // and fix the presentation to be the same.
21297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final String[] absentNumberValues =
21307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                context.getResources().getStringArray(R.array.absent_num);
21317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (Arrays.asList(absentNumberValues).contains(number)
21327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                && presentation == PhoneConstants.PRESENTATION_ALLOWED) {
21337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            number = context.getString(R.string.unknown);
21347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            ci.numberPresentation = PhoneConstants.PRESENTATION_UNKNOWN;
21357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
21367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
21377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Check for other special "corner cases" for CNAP and fix them similarly. Corner
21387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // cases only apply if we received an allowed presentation from the network, so check
21397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // if we think we have an allowed presentation, or if the CallerInfo presentation doesn't
21407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // match the presentation passed in for verification (meaning we changed it previously
21417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // because it's a corner case and we're being called from a different entry point).
21427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (ci.numberPresentation == PhoneConstants.PRESENTATION_ALLOWED
21437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                || (ci.numberPresentation != presentation
21447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        && presentation == PhoneConstants.PRESENTATION_ALLOWED)) {
21457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            int cnapSpecialCase = checkCnapSpecialCases(number);
21467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (cnapSpecialCase != CNAP_SPECIAL_CASE_NO) {
21477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // For all special strings, change number & numberPresentation.
21487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (cnapSpecialCase == PhoneConstants.PRESENTATION_RESTRICTED) {
21497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    number = context.getString(R.string.private_num);
21507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                } else if (cnapSpecialCase == PhoneConstants.PRESENTATION_UNKNOWN) {
21517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    number = context.getString(R.string.unknown);
21527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
21537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (DBG) {
21547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    log("SpecialCnap: number=" + toLogSafePhoneNumber(number)
21557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            + "; presentation now=" + cnapSpecialCase);
21567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
21577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                ci.numberPresentation = cnapSpecialCase;
21587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
21597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
21607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) {
21617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            log("modifyForSpecialCnapCases: returning number string="
21627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    + toLogSafePhoneNumber(number));
21637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
21647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return number;
21657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
21667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
21677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    //
21687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    // Support for 3rd party phone service providers.
21697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    //
21707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
21717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
21727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Check if a phone number can be route through a 3rd party
21737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * gateway. The number must be a global phone number in numerical
21747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * form (1-800-666-SEXY won't work).
21757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
21767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * MMI codes and the like cannot be used as a dial number for the
21777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * gateway either.
21787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
21797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param number To be dialed via a 3rd party gateway.
21807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return true If the number can be routed through the 3rd party network.
21817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
218269a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon    private static boolean isRoutableViaGateway(String number) {
21837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (TextUtils.isEmpty(number)) {
21847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return false;
21857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
21867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        number = PhoneNumberUtils.stripSeparators(number);
21877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (!number.equals(PhoneNumberUtils.convertKeypadLettersToDigits(number))) {
21887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return false;
21897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
21907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        number = PhoneNumberUtils.extractNetworkPortion(number);
21917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return PhoneNumberUtils.isGlobalPhoneNumber(number);
21927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
21937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
21947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon   /**
21957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    * This function is called when phone answers or places a call.
21967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    * Check if the phone is in a car dock or desk dock.
21977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    * If yes, turn on the speaker, when no wired or BT headsets are connected.
21987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    * Otherwise do nothing.
21997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    * @return true if activated
22007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    */
22017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static boolean activateSpeakerIfDocked(Phone phone) {
22027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("activateSpeakerIfDocked()...");
22037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
22047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        boolean activated = false;
22057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (PhoneGlobals.mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED) {
22067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG) log("activateSpeakerIfDocked(): In a dock -> may need to turn on speaker.");
2207593ab38970a84a60ac39edba4306647c8b66436dSantos Cordon            final PhoneGlobals app = PhoneGlobals.getInstance();
2208593ab38970a84a60ac39edba4306647c8b66436dSantos Cordon
22093e0f0414daa2266dc51b77198fe433797f7d610aChristine Chen            // TODO: This function should move to AudioRouter
221027a3c1f96fab43970e56a5eaa39551a4a248994fSantos Cordon            final BluetoothManager btManager = app.getBluetoothManager();
2211bb2bcef62b916b1b544195ca671d56af6ed32cc2Santos Cordon            //final WiredHeadsetManager wiredHeadset = app.getWiredHeadsetManager();
2212bb2bcef62b916b1b544195ca671d56af6ed32cc2Santos Cordon            //final AudioRouter audioRouter = app.getAudioRouter();
22137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2214bb2bcef62b916b1b544195ca671d56af6ed32cc2Santos Cordon            /*if (!wiredHeadset.isHeadsetPlugged() && !btManager.isBluetoothHeadsetAudioOn()) {
2215bb2bcef62b916b1b544195ca671d56af6ed32cc2Santos Cordon                //audioRouter.setSpeaker(true);
22167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                activated = true;
2217bb2bcef62b916b1b544195ca671d56af6ed32cc2Santos Cordon            }*/
22187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
22197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return activated;
22207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
22217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
22227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
22237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
22247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Returns whether the phone is in ECM ("Emergency Callback Mode") or not.
22257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
22267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /* package */ static boolean isPhoneInEcm(Phone phone) {
22277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if ((phone != null) && TelephonyCapabilities.supportsEcm(phone)) {
22287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // For phones that support ECM, return true iff PROPERTY_INECM_MODE == "true".
22297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // TODO: There ought to be a better API for this than just
22307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // exposing a system property all the way up to the app layer,
22317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // probably a method like "inEcm()" provided by the telephony
22327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // layer.
22337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            String ecmMode =
22347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE);
22357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (ecmMode != null) {
22367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                return ecmMode.equals("true");
22377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
22387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
22397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return false;
22407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
22417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
22427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
22437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Returns the most appropriate Phone object to handle a call
22447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * to the specified number.
22457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
22467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param cm the CallManager.
22477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param scheme the scheme from the data URI that the number originally came from.
22487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param number the phone number, or SIP address.
22497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
2250bfb6832c4bcc535aef12b07ac5bcf4a973c65d00Sailesh Nepal    public static Phone pickPhoneBasedOnNumber(CallManager cm, String scheme, String number,
2251bfb6832c4bcc535aef12b07ac5bcf4a973c65d00Sailesh Nepal            String primarySipUri, ComponentName thirdPartyCallComponent) {
22527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) {
22537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            log("pickPhoneBasedOnNumber: scheme " + scheme
22547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    + ", number " + toLogSafePhoneNumber(number)
22557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    + ", sipUri "
2256bfb6832c4bcc535aef12b07ac5bcf4a973c65d00Sailesh Nepal                    + (primarySipUri != null ? Uri.parse(primarySipUri).toSafeString() : "null")
2257bfb6832c4bcc535aef12b07ac5bcf4a973c65d00Sailesh Nepal                    + ", thirdPartyCallComponent: " + thirdPartyCallComponent);
22587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
22597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
22607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (primarySipUri != null) {
22617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Phone phone = getSipPhoneFromUri(cm, primarySipUri);
22627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (phone != null) return phone;
22637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
2264bfb6832c4bcc535aef12b07ac5bcf4a973c65d00Sailesh Nepal
22657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return cm.getDefaultPhone();
22667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
22677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
22687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public static Phone getSipPhoneFromUri(CallManager cm, String target) {
22697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        for (Phone phone : cm.getAllPhones()) {
22707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_SIP) {
22717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                String sipUri = ((SipPhone) phone).getSipUri();
22727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (target.equals(sipUri)) {
22737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    if (DBG) log("- pickPhoneBasedOnNumber:" +
22747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            "found SipPhone! obj = " + phone + ", "
22757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            + phone.getClass());
22767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    return phone;
22777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
22787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
22797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
22807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return null;
22817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
22827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
22837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
22847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Returns true when the given call is in INCOMING state and there's no foreground phone call,
22857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * meaning the call is the first real incoming call the phone is having.
22867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
22877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public static boolean isRealIncomingCall(Call.State state) {
22887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return (state == Call.State.INCOMING && !PhoneGlobals.getInstance().mCM.hasActiveFgCall());
22897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
22907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
22917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public static String getPresentationString(Context context, int presentation) {
22927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        String name = context.getString(R.string.unknown);
22937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (presentation == PhoneConstants.PRESENTATION_RESTRICTED) {
22947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            name = context.getString(R.string.private_num);
22957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else if (presentation == PhoneConstants.PRESENTATION_PAYPHONE) {
22967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            name = context.getString(R.string.payphone);
22977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
22987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return name;
22997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
23007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
23017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public static void sendViewNotificationAsync(Context context, Uri contactUri) {
23027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) Log.d(LOG_TAG, "Send view notification to Contacts (uri: " + contactUri + ")");
23037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Intent intent = new Intent("com.android.contacts.VIEW_NOTIFICATION", contactUri);
23047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        intent.setClassName("com.android.contacts",
23057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                "com.android.contacts.ViewNotificationService");
23067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        context.startService(intent);
23077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
23087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
23097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    //
23107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    // General phone and call state debugging/testing code
23117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    //
23127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
23137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /* package */ static void dumpCallState(Phone phone) {
23147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        PhoneGlobals app = PhoneGlobals.getInstance();
23157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Log.d(LOG_TAG, "dumpCallState():");
23167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Log.d(LOG_TAG, "- Phone: " + phone + ", name = " + phone.getPhoneName()
23177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon              + ", state = " + phone.getState());
23187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
23197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        StringBuilder b = new StringBuilder(128);
23207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
23217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Call call = phone.getForegroundCall();
23227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.setLength(0);
23237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append("  - FG call: ").append(call.getState());
23247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" isAlive ").append(call.getState().isAlive());
23257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" isRinging ").append(call.getState().isRinging());
23267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" isDialing ").append(call.getState().isDialing());
23277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" isIdle ").append(call.isIdle());
23287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" hasConnections ").append(call.hasConnections());
23297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Log.d(LOG_TAG, b.toString());
23307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
23317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        call = phone.getBackgroundCall();
23327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.setLength(0);
23337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append("  - BG call: ").append(call.getState());
23347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" isAlive ").append(call.getState().isAlive());
23357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" isRinging ").append(call.getState().isRinging());
23367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" isDialing ").append(call.getState().isDialing());
23377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" isIdle ").append(call.isIdle());
23387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" hasConnections ").append(call.hasConnections());
23397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Log.d(LOG_TAG, b.toString());
23407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
23417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        call = phone.getRingingCall();
23427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.setLength(0);
23437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append("  - RINGING call: ").append(call.getState());
23447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" isAlive ").append(call.getState().isAlive());
23457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" isRinging ").append(call.getState().isRinging());
23467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" isDialing ").append(call.getState().isDialing());
23477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" isIdle ").append(call.isIdle());
23487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" hasConnections ").append(call.hasConnections());
23497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Log.d(LOG_TAG, b.toString());
23507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
23517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
23527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final boolean hasRingingCall = !phone.getRingingCall().isIdle();
23537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final boolean hasActiveCall = !phone.getForegroundCall().isIdle();
23547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final boolean hasHoldingCall = !phone.getBackgroundCall().isIdle();
23557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final boolean allLinesTaken = hasActiveCall && hasHoldingCall;
23567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.setLength(0);
23577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append("  - hasRingingCall ").append(hasRingingCall);
23587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" hasActiveCall ").append(hasActiveCall);
23597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" hasHoldingCall ").append(hasHoldingCall);
23607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" allLinesTaken ").append(allLinesTaken);
23617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Log.d(LOG_TAG, b.toString());
23627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
23637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // On CDMA phones, dump out the CdmaPhoneCallState too:
23647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {
23657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (app.cdmaPhoneCallState != null) {
23667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Log.d(LOG_TAG, "  - CDMA call state: "
23677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                      + app.cdmaPhoneCallState.getCurrentCallState());
23687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            } else {
23697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Log.d(LOG_TAG, "  - CDMA device, but null cdmaPhoneCallState!");
23707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
23717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
23727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
23737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
23747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static void log(String msg) {
23757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Log.d(LOG_TAG, msg);
23767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
23777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
23787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    static void dumpCallManager() {
23797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Call call;
23807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        CallManager cm = PhoneGlobals.getInstance().mCM;
23817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        StringBuilder b = new StringBuilder(128);
23827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
23837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
23847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
23857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Log.d(LOG_TAG, "############### dumpCallManager() ##############");
23867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // TODO: Don't log "cm" itself, since CallManager.toString()
23877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // already spews out almost all this same information.
23887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // We should fix CallManager.toString() to be more minimal, and
23897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // use an explicit dumpState() method for the verbose dump.
23907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Log.d(LOG_TAG, "CallManager: " + cm
23917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //         + ", state = " + cm.getState());
23927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Log.d(LOG_TAG, "CallManager: state = " + cm.getState());
23937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.setLength(0);
23947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        call = cm.getActiveFgCall();
23957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" - FG call: ").append(cm.hasActiveFgCall()? "YES ": "NO ");
23967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(call);
23977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append( "  State: ").append(cm.getActiveFgCallState());
23987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append( "  Conn: ").append(cm.getFgCallConnections());
23997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Log.d(LOG_TAG, b.toString());
24007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.setLength(0);
24017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        call = cm.getFirstActiveBgCall();
24027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" - BG call: ").append(cm.hasActiveBgCall()? "YES ": "NO ");
24037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(call);
24047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append( "  State: ").append(cm.getFirstActiveBgCall().getState());
24057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append( "  Conn: ").append(cm.getBgCallConnections());
24067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Log.d(LOG_TAG, b.toString());
24077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.setLength(0);
24087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        call = cm.getFirstActiveRingingCall();
24097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(" - RINGING call: ").append(cm.hasActiveRingingCall()? "YES ": "NO ");
24107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append(call);
24117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        b.append( "  State: ").append(cm.getFirstActiveRingingCall().getState());
24127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Log.d(LOG_TAG, b.toString());
24137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
24147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
24157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
24167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        for (Phone phone : CallManager.getInstance().getAllPhones()) {
24177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (phone != null) {
24187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Log.d(LOG_TAG, "Phone: " + phone + ", name = " + phone.getPhoneName()
24197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        + ", state = " + phone.getState());
24207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                b.setLength(0);
24217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                call = phone.getForegroundCall();
24227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                b.append(" - FG call: ").append(call);
24237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                b.append( "  State: ").append(call.getState());
24247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                b.append( "  Conn: ").append(call.hasConnections());
24257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Log.d(LOG_TAG, b.toString());
24267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                b.setLength(0);
24277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                call = phone.getBackgroundCall();
24287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                b.append(" - BG call: ").append(call);
24297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                b.append( "  State: ").append(call.getState());
24307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                b.append( "  Conn: ").append(call.hasConnections());
24317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Log.d(LOG_TAG, b.toString());b.setLength(0);
24327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                call = phone.getRingingCall();
24337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                b.append(" - RINGING call: ").append(call);
24347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                b.append( "  State: ").append(call.getState());
24357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                b.append( "  Conn: ").append(call.hasConnections());
24367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Log.d(LOG_TAG, b.toString());
24377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
24387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
24397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
24407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Log.d(LOG_TAG, "############## END dumpCallManager() ###############");
24417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
24427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
24437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
24447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return if the context is in landscape orientation.
24457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
24467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public static boolean isLandscape(Context context) {
24477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        return context.getResources().getConfiguration().orientation
24487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                == Configuration.ORIENTATION_LANDSCAPE;
24497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
2450d5165b05c851ecd47d330b600ed2768e0db8b9d1Andrew Lee
2451d5165b05c851ecd47d330b600ed2768e0db8b9d1Andrew Lee    public static PhoneAccountHandle makePstnPhoneAccountHandle(Phone phone) {
2452d5165b05c851ecd47d330b600ed2768e0db8b9d1Andrew Lee        return makePstnPhoneAccountHandleWithPrefix(phone, "", false);
2453d5165b05c851ecd47d330b600ed2768e0db8b9d1Andrew Lee    }
2454d5165b05c851ecd47d330b600ed2768e0db8b9d1Andrew Lee
2455d5165b05c851ecd47d330b600ed2768e0db8b9d1Andrew Lee    public static PhoneAccountHandle makePstnPhoneAccountHandleWithPrefix(
2456d5165b05c851ecd47d330b600ed2768e0db8b9d1Andrew Lee            Phone phone, String prefix, boolean isEmergency) {
2457f69df96f713523a8b078aa6ef922e3e752a1a594Santos Cordon        ComponentName pstnConnectionServiceName = getPstnConnectionServiceName();
2458d5165b05c851ecd47d330b600ed2768e0db8b9d1Andrew Lee        // TODO: Should use some sort of special hidden flag to decorate this account as
2459d5165b05c851ecd47d330b600ed2768e0db8b9d1Andrew Lee        // an emergency-only account
2460d5165b05c851ecd47d330b600ed2768e0db8b9d1Andrew Lee        String id = isEmergency ? "E" : prefix + String.valueOf(phone.getSubId());
2461d5165b05c851ecd47d330b600ed2768e0db8b9d1Andrew Lee        return new PhoneAccountHandle(pstnConnectionServiceName, id);
2462d5165b05c851ecd47d330b600ed2768e0db8b9d1Andrew Lee    }
2463dcf40a9cc562d95f826123d8d670262c8d15e7bdStuart Scott
2464f69df96f713523a8b078aa6ef922e3e752a1a594Santos Cordon    public static int getSubIdForPhoneAccount(PhoneAccount phoneAccount) {
2465f69df96f713523a8b078aa6ef922e3e752a1a594Santos Cordon        if (phoneAccount != null) {
2466f69df96f713523a8b078aa6ef922e3e752a1a594Santos Cordon            PhoneAccountHandle handle = phoneAccount.getAccountHandle();
2467f69df96f713523a8b078aa6ef922e3e752a1a594Santos Cordon            if (handle != null && handle.getComponentName().equals(getPstnConnectionServiceName()) &&
2468f69df96f713523a8b078aa6ef922e3e752a1a594Santos Cordon                    phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
2469f69df96f713523a8b078aa6ef922e3e752a1a594Santos Cordon                String id = handle.getId();
2470f69df96f713523a8b078aa6ef922e3e752a1a594Santos Cordon                if (TextUtils.isDigitsOnly(id)) {
2471f69df96f713523a8b078aa6ef922e3e752a1a594Santos Cordon                    return Integer.parseInt(id);
2472f69df96f713523a8b078aa6ef922e3e752a1a594Santos Cordon                }
2473f69df96f713523a8b078aa6ef922e3e752a1a594Santos Cordon            }
2474f69df96f713523a8b078aa6ef922e3e752a1a594Santos Cordon        }
2475f69df96f713523a8b078aa6ef922e3e752a1a594Santos Cordon        return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
2476f69df96f713523a8b078aa6ef922e3e752a1a594Santos Cordon    }
2477f69df96f713523a8b078aa6ef922e3e752a1a594Santos Cordon
2478f69df96f713523a8b078aa6ef922e3e752a1a594Santos Cordon    private static ComponentName getPstnConnectionServiceName() {
2479f69df96f713523a8b078aa6ef922e3e752a1a594Santos Cordon        return new ComponentName(PhoneGlobals.getInstance(), TelephonyConnectionService.class);
2480f69df96f713523a8b078aa6ef922e3e752a1a594Santos Cordon    }
2481f69df96f713523a8b078aa6ef922e3e752a1a594Santos Cordon
2482dcf40a9cc562d95f826123d8d670262c8d15e7bdStuart Scott    /**
2483dcf40a9cc562d95f826123d8d670262c8d15e7bdStuart Scott     * Register ICC status for all phones.
2484dcf40a9cc562d95f826123d8d670262c8d15e7bdStuart Scott     */
2485dcf40a9cc562d95f826123d8d670262c8d15e7bdStuart Scott    static final void registerIccStatus(Handler handler, int event) {
2486dcf40a9cc562d95f826123d8d670262c8d15e7bdStuart Scott        for (Phone phone : PhoneFactory.getPhones()) {
2487dcf40a9cc562d95f826123d8d670262c8d15e7bdStuart Scott            IccCard sim = phone.getIccCard();
2488dcf40a9cc562d95f826123d8d670262c8d15e7bdStuart Scott            if (sim != null) {
2489dcf40a9cc562d95f826123d8d670262c8d15e7bdStuart Scott                if (VDBG) Log.v(LOG_TAG, "register for ICC status, phone " + phone.getPhoneId());
2490dcf40a9cc562d95f826123d8d670262c8d15e7bdStuart Scott                sim.registerForNetworkLocked(handler, event, phone);
2491dcf40a9cc562d95f826123d8d670262c8d15e7bdStuart Scott            }
2492dcf40a9cc562d95f826123d8d670262c8d15e7bdStuart Scott        }
2493dcf40a9cc562d95f826123d8d670262c8d15e7bdStuart Scott    }
2494dcf40a9cc562d95f826123d8d670262c8d15e7bdStuart Scott
2495dcf40a9cc562d95f826123d8d670262c8d15e7bdStuart Scott    /**
2496dcf40a9cc562d95f826123d8d670262c8d15e7bdStuart Scott     * Set the radio power on/off state for all phones.
2497dcf40a9cc562d95f826123d8d670262c8d15e7bdStuart Scott     *
2498dcf40a9cc562d95f826123d8d670262c8d15e7bdStuart Scott     * @param enabled true means on, false means off.
2499dcf40a9cc562d95f826123d8d670262c8d15e7bdStuart Scott     */
2500dcf40a9cc562d95f826123d8d670262c8d15e7bdStuart Scott    static final void setRadioPower(boolean enabled) {
2501dcf40a9cc562d95f826123d8d670262c8d15e7bdStuart Scott        for (Phone phone : PhoneFactory.getPhones()) {
2502dcf40a9cc562d95f826123d8d670262c8d15e7bdStuart Scott            phone.setRadioPower(enabled);
2503dcf40a9cc562d95f826123d8d670262c8d15e7bdStuart Scott        }
2504dcf40a9cc562d95f826123d8d670262c8d15e7bdStuart Scott    }
25057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon}
2506