17d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon/*
27d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon * Copyright (C) 2011 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 com.android.internal.telephony.CallManager;
207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport com.android.internal.telephony.Phone;
217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport com.android.internal.telephony.PhoneConstants;
227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport com.android.internal.telephony.TelephonyCapabilities;
2369a691914e9b013a7ff52c129d8466c152ed7239Santos Cordonimport com.android.phone.CallGatewayManager.RawGatewayInfo;
247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport com.android.phone.Constants.CallStatusCode;
2571028d0df4f699670dd7838011741c1cd9464061Yorke Leeimport com.android.phone.ErrorDialogActivity;
267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.content.Intent;
287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.net.Uri;
297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.os.Handler;
307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.os.Message;
317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.os.SystemProperties;
327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.provider.CallLog.Calls;
337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.telephony.PhoneNumberUtils;
347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.telephony.ServiceState;
357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonimport android.util.Log;
367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon/**
387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon * Phone app module in charge of "call control".
397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon *
407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon * This is a singleton object which acts as the interface to the telephony layer
417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon * (and other parts of the Android framework) for all user-initiated telephony
427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon * functionality, like making outgoing calls.
437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon *
447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon * This functionality includes things like:
457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon *   - actually running the placeCall() method and handling errors or retries
467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon *   - running the whole "emergency call in airplane mode" sequence
477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon *   - running the state machine of MMI sequences
487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon *   - restoring/resetting mute and speaker state when a new call starts
497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon *   - updating the prox sensor wake lock state
507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon *   - resolving what the voicemail: intent should mean (and making the call)
517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon *
527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon * The single CallController instance stays around forever; it's not tied
537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon * to the lifecycle of any particular Activity (like the InCallScreen).
547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon * There's also no implementation of onscreen UI here (that's all in InCallScreen).
557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon *
567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon * Note that this class does not handle asynchronous events from the telephony
577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon * layer, like reacting to an incoming call; see CallNotifier for that.  This
587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon * class purely handles actions initiated by the user, like outgoing calls.
597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon */
607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordonpublic class CallController extends Handler {
617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static final String TAG = "CallController";
627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static final boolean DBG =
637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            (PhoneGlobals.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1);
647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    // Do not check in with VDBG = true, since that may write PII to the system log.
657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static final boolean VDBG = false;
667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /** The singleton CallController instance. */
687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static CallController sInstance;
697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
7069a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon    final private PhoneGlobals mApp;
7169a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon    final private CallManager mCM;
7269a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon    final private CallLogger mCallLogger;
7369a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon    final private CallGatewayManager mCallGatewayManager;
747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /** Helper object for emergency calls in some rare use cases.  Created lazily. */
767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private EmergencyCallHelper mEmergencyCallHelper;
777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    //
807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    // Message codes; see handleMessage().
817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    //
827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static final int THREEWAY_CALLERINFO_DISPLAY_DONE = 1;
847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    //
877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    // Misc constants.
887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    //
897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    // Amount of time the UI should display "Dialing" when initiating a CDMA
917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    // 3way call.  (See comments on the THRWAY_ACTIVE case in
927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    // placeCallInternal() for more info.)
937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static final int THREEWAY_CALLERINFO_DISPLAY_TIME = 3000; // msec
947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Initialize the singleton CallController instance.
987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * This is only done once, at startup, from PhoneApp.onCreate().
1007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * From then on, the CallController instance is available via the
1017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * PhoneApp's public "callController" field, which is why there's no
1027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * getInstance() method here.
1037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
10469a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon    /* package */ static CallController init(PhoneGlobals app, CallLogger callLogger,
10569a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon            CallGatewayManager callGatewayManager) {
1067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        synchronized (CallController.class) {
1077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (sInstance == null) {
10869a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon                sInstance = new CallController(app, callLogger, callGatewayManager);
1097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            } else {
1107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Log.wtf(TAG, "init() called multiple times!  sInstance = " + sInstance);
1117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
1127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return sInstance;
1137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
1147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
1157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
1177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Private constructor (this is a singleton).
1187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @see init()
1197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
12069a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon    private CallController(PhoneGlobals app, CallLogger callLogger,
12169a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon            CallGatewayManager callGatewayManager) {
1227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("CallController constructor: app = " + app);
1237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        mApp = app;
1247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        mCM = app.mCM;
1257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        mCallLogger = callLogger;
12669a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon        mCallGatewayManager = callGatewayManager;
1277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
1287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    @Override
1307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public void handleMessage(Message msg) {
1317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (VDBG) log("handleMessage: " + msg);
1327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        switch (msg.what) {
1337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            case THREEWAY_CALLERINFO_DISPLAY_DONE:
1357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (DBG) log("THREEWAY_CALLERINFO_DISPLAY_DONE...");
1367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (mApp.cdmaPhoneCallState.getCurrentCallState()
1387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    == CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE) {
1397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // Reset the mThreeWayCallOrigStateDialing state
1407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    mApp.cdmaPhoneCallState.setThreeWayCallOrigState(false);
1417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
142ad1ed6d23c4a999a41bb73b8243009e32f96d7dfSantos Cordon                    mApp.getCallModeler().setCdmaOutgoing3WayCall(null);
1437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
1447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                break;
1457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            default:
1477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Log.wtf(TAG, "handleMessage: unexpected code: " + msg);
1487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                break;
1497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
1507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
1517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    //
1537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    // Outgoing call sequence
1547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    //
1557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
1577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Initiate an outgoing call.
1587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
1597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Here's the most typical outgoing call sequence:
1607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
1617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *  (1) OutgoingCallBroadcaster receives a CALL intent and sends the
1627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *      NEW_OUTGOING_CALL broadcast
1637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
1647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *  (2) The broadcast finally reaches OutgoingCallReceiver, which stashes
1657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *      away a copy of the original CALL intent and launches
1667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *      SipCallOptionHandler
1677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
1687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *  (3) SipCallOptionHandler decides whether this is a PSTN or SIP call (and
1697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *      in some cases brings up a dialog to let the user choose), and
1707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *      ultimately calls CallController.placeCall() (from the
1717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *      setResultAndFinish() method) with the stashed-away intent from step
1727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *      (2) as the "intent" parameter.
1737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
1747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *  (4) Here in CallController.placeCall() we read the phone number or SIP
1757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *      address out of the intent and actually initiate the call, and
1767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *      simultaneously launch the InCallScreen to display the in-call UI.
1777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
1787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *  (5) We handle various errors by directing the InCallScreen to
1797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *      display error messages or dialogs (via the InCallUiState
1807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *      "pending call status code" flag), and in some cases we also
1817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *      sometimes continue working in the background to resolve the
1827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *      problem (like in the case of an emergency call while in
1837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *      airplane mode).  Any time that some onscreen indication to the
1847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *      user needs to change, we update the "status dialog" info in
1857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *      the inCallUiState and (re)launch the InCallScreen to make sure
1867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *      it's visible.
1877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
1887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    public void placeCall(Intent intent) {
1897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        log("placeCall()...  intent = " + intent);
1907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (VDBG) log("                extras = " + intent.getExtras());
1917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // TODO: Do we need to hold a wake lock while this method runs?
1937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //       Or did we already acquire one somewhere earlier
1947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //       in this sequence (like when we first received the CALL intent?)
1957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
1967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (intent == null) {
1977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Log.wtf(TAG, "placeCall: called with null intent");
1987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            throw new IllegalArgumentException("placeCall: called with null intent");
1997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
2007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        String action = intent.getAction();
2027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Uri uri = intent.getData();
2037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (uri == null) {
2047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Log.wtf(TAG, "placeCall: intent had no data");
2057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            throw new IllegalArgumentException("placeCall: intent had no data");
2067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
2077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        String scheme = uri.getScheme();
2097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        String number = PhoneNumberUtils.getNumberFromIntent(intent, mApp);
2107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (VDBG) {
2117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            log("- action: " + action);
2127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            log("- uri: " + uri);
2137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            log("- scheme: " + scheme);
2147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            log("- number: " + number);
2157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
2167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // This method should only be used with the various flavors of CALL
2187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // intents.  (It doesn't make sense for any other action to trigger an
2197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // outgoing call!)
2207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (!(Intent.ACTION_CALL.equals(action)
2217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon              || Intent.ACTION_CALL_EMERGENCY.equals(action)
2227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon              || Intent.ACTION_CALL_PRIVILEGED.equals(action))) {
2237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Log.wtf(TAG, "placeCall: unexpected intent action " + action);
2247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            throw new IllegalArgumentException("Unexpected action: " + action);
2257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
2267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Check to see if this is an OTASP call (the "activation" call
2287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // used to provision CDMA devices), and if so, do some
2297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // OTASP-specific setup.
2307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Phone phone = mApp.mCM.getDefaultPhone();
2317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (TelephonyCapabilities.supportsOtasp(phone)) {
2327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            checkForOtaspCall(intent);
2337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
2347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Clear out the "restore mute state" flag since we're
2367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // initiating a brand-new call.
2377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //
2387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // (This call to setRestoreMuteOnInCallResume(false) informs the
2397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // phone app that we're dealing with a new connection
2407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // (i.e. placing an outgoing call, and NOT handling an aborted
2417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // "Add Call" request), so we should let the mute state be handled
2427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // by the PhoneUtils phone state change handler.)
2437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        mApp.setRestoreMuteOnInCallResume(false);
2447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        CallStatusCode status = placeCallInternal(intent);
2467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        switch (status) {
2487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // Call was placed successfully:
2497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            case SUCCESS:
2507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            case EXITED_ECM:
2517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (DBG) log("==> placeCall(): success from placeCallInternal(): " + status);
2527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                break;
2537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            default:
2557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // Any other status code is a failure.
2567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                log("==> placeCall(): failure code from placeCallInternal(): " + status);
2577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // Handle the various error conditions that can occur when
2587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // initiating an outgoing call, typically by directing the
2597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // InCallScreen to display a diagnostic message (via the
2607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // "pending call status code" flag.)
2617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                handleOutgoingCallError(status);
2627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                break;
2637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
2647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Finally, regardless of whether we successfully initiated the
2667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // outgoing call or not, force the InCallScreen to come to the
2677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // foreground.
2687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //
2697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // (For successful calls the the user will just see the normal
2707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // in-call UI.  Or if there was an error, the InCallScreen will
2717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // notice the InCallUiState pending call status code flag and display an
2727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // error indication instead.)
2737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
2747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
2767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Actually make a call to whomever the intent tells us to.
2777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
2787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Note that there's no need to explicitly update (or refresh) the
2797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * in-call UI at any point in this method, since a fresh InCallScreen
2807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * instance will be launched automatically after we return (see
2817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * placeCall() above.)
2827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
2837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param intent the CALL intent describing whom to call
2847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return CallStatusCode.SUCCESS if we successfully initiated an
2857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *    outgoing call.  If there was some kind of failure, return one of
2867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *    the other CallStatusCode codes indicating what went wrong.
2877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
2887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private CallStatusCode placeCallInternal(Intent intent) {
2897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("placeCallInternal()...  intent = " + intent);
2907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // TODO: This method is too long.  Break it down into more
2927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // manageable chunks.
2937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final Uri uri = intent.getData();
2957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        final String scheme = (uri != null) ? uri.getScheme() : null;
2967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        String number;
2977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Phone phone = null;
2987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
2997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Check the current ServiceState to make sure it's OK
3007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // to even try making a call.
3017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        CallStatusCode okToCallStatus = checkIfOkToInitiateOutgoingCall(
3027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                mCM.getServiceState());
3037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
3047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // TODO: Streamline the logic here.  Currently, the code is
3057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // unchanged from its original form in InCallScreen.java.  But we
3067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // should fix a couple of things:
3077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // - Don't call checkIfOkToInitiateOutgoingCall() more than once
3087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // - Wrap the try/catch for VoiceMailNumberMissingException
3097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //   around *only* the call that can throw that exception.
3107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
3117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        try {
3127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            number = PhoneUtils.getInitialNumber(intent);
3137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (VDBG) log("- actual number to dial: '" + number + "'");
3147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
3157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // find the phone first
3167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // TODO Need a way to determine which phone to place the call
3177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // It could be determined by SIP setting, i.e. always,
3187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // or by number, i.e. for international,
3197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // or by user selection, i.e., dialog query,
3207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // or any of combinations
3217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            String sipPhoneUri = intent.getStringExtra(
3227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    OutgoingCallBroadcaster.EXTRA_SIP_PHONE_URI);
3237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            phone = PhoneUtils.pickPhoneBasedOnNumber(mCM, scheme, number, sipPhoneUri);
3247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (VDBG) log("- got Phone instance: " + phone + ", class = " + phone.getClass());
3257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
3267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // update okToCallStatus based on new phone
3277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            okToCallStatus = checkIfOkToInitiateOutgoingCall(
3287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    phone.getServiceState().getState());
3297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
3307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } catch (PhoneUtils.VoiceMailNumberMissingException ex) {
3317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // If the call status is NOT in an acceptable state, it
3327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // may effect the way the voicemail number is being
3337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // retrieved.  Mask the VoiceMailNumberMissingException
3347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // with the underlying issue of the phone state.
3357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (okToCallStatus != CallStatusCode.SUCCESS) {
3367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (DBG) log("Voicemail number not reachable in current SIM card state.");
3377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                return okToCallStatus;
3387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
3397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG) log("VoiceMailNumberMissingException from getInitialNumber()");
3407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return CallStatusCode.VOICEMAIL_NUMBER_MISSING;
3417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
3427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
3437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (number == null) {
3447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Log.w(TAG, "placeCall: couldn't get a phone number from Intent " + intent);
3457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return CallStatusCode.NO_PHONE_NUMBER_SUPPLIED;
3467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
3477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
3487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
3497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Sanity-check that ACTION_CALL_EMERGENCY is used if and only if
3507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // this is a call to an emergency number
3517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // (This is just a sanity-check; this policy *should* really be
3527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // enforced in OutgoingCallBroadcaster.onCreate(), which is the
3537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // main entry point for the CALL and CALL_* intents.)
3547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        boolean isEmergencyNumber = PhoneNumberUtils.isLocalEmergencyNumber(number, mApp);
3557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        boolean isPotentialEmergencyNumber =
3567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                PhoneNumberUtils.isPotentialLocalEmergencyNumber(number, mApp);
3577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        boolean isEmergencyIntent = Intent.ACTION_CALL_EMERGENCY.equals(intent.getAction());
3587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
3597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (isPotentialEmergencyNumber && !isEmergencyIntent) {
3607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Log.e(TAG, "Non-CALL_EMERGENCY Intent " + intent
3617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    + " attempted to call potential emergency number " + number
3627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    + ".");
3637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return CallStatusCode.CALL_FAILED;
3647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else if (!isPotentialEmergencyNumber && isEmergencyIntent) {
3657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Log.e(TAG, "Received CALL_EMERGENCY Intent " + intent
3667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    + " with non-potential-emergency number " + number
3677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    + " -- failing call.");
3687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            return CallStatusCode.CALL_FAILED;
3697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
3707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
3717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // If we're trying to call an emergency number, then it's OK to
3727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // proceed in certain states where we'd otherwise bring up
3737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // an error dialog:
3747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // - If we're in EMERGENCY_ONLY mode, then (obviously) you're allowed
3757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //   to dial emergency numbers.
3767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // - If we're OUT_OF_SERVICE, we still attempt to make a call,
3777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        //   since the radio will register to any available network.
3787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
3797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (isEmergencyNumber
3807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            && ((okToCallStatus == CallStatusCode.EMERGENCY_ONLY)
3817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                || (okToCallStatus == CallStatusCode.OUT_OF_SERVICE))) {
3827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG) log("placeCall: Emergency number detected with status = " + okToCallStatus);
3837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            okToCallStatus = CallStatusCode.SUCCESS;
3847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG) log("==> UPDATING status to: " + okToCallStatus);
3857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
3867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
3877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (okToCallStatus != CallStatusCode.SUCCESS) {
3887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // If this is an emergency call, launch the EmergencyCallHelperService
3897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // to turn on the radio and retry the call.
3907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (isEmergencyNumber && (okToCallStatus == CallStatusCode.POWER_OFF)) {
3917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Log.i(TAG, "placeCall: Trying to make emergency call while POWER_OFF!");
3927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
3937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // If needed, lazily instantiate an EmergencyCallHelper instance.
3947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                synchronized (this) {
3957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    if (mEmergencyCallHelper == null) {
3967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        mEmergencyCallHelper = new EmergencyCallHelper(this);
3977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    }
3987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
3997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // ...and kick off the "emergency call from airplane mode" sequence.
4017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                mEmergencyCallHelper.startEmergencyCallFromAirplaneModeSequence(number);
4027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // Finally, return CallStatusCode.SUCCESS right now so
4047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // that the in-call UI will remain visible (in order to
4057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // display the progress indication.)
4067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // TODO: or maybe it would be more clear to return a whole
4077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // new CallStatusCode called "TURNING_ON_RADIO" here.
4087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // That way, we'd update inCallUiState.progressIndication from
4097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // the handleOutgoingCallError() method, rather than here.
4107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                return CallStatusCode.SUCCESS;
4117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            } else {
4127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // Otherwise, just return the (non-SUCCESS) status code
4137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // back to our caller.
4147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (DBG) log("==> placeCallInternal(): non-success status: " + okToCallStatus);
4157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // Log failed call.
4177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // Note: Normally, many of these values we gather from the Connection object but
4187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // since no such object is created for unconnected calls, we have to build them
4197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // manually.
4207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // TODO(santoscordon): Try to restructure code so that we can handle failure-
4217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // condition call logging in a single place (placeCall()) that also has access to
4227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // the number we attempted to dial (not placeCall()).
4237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                mCallLogger.logCall(null /* callerInfo */, number, 0 /* presentation */,
4247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        Calls.OUTGOING_TYPE, System.currentTimeMillis(), 0 /* duration */);
4257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                return okToCallStatus;
4277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            }
4287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
4297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // We have a valid number, so try to actually place a call:
4317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // make sure we pass along the intent's URI which is a
4327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // reference to the contact. We may have a provider gateway
4337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // phone number to use for the outgoing call.
4347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Uri contactUri = intent.getData();
4357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
43669a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon        // If a gateway is used, extract the data here and pass that into placeCall.
43769a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon        final RawGatewayInfo rawGatewayInfo = mCallGatewayManager.getRawGatewayInfo(intent, number);
43869a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon
4397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // Watch out: PhoneUtils.placeCall() returns one of the
4407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        // CALL_STATUS_* constants, not a CallStatusCode enum value.
4417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        int callStatus = PhoneUtils.placeCall(mApp,
4427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                              phone,
4437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                              number,
4447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                              contactUri,
4457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                              (isEmergencyNumber || isEmergencyIntent),
44669a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon                                              rawGatewayInfo,
44769a691914e9b013a7ff52c129d8466c152ed7239Santos Cordon                                              mCallGatewayManager);
4487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        switch (callStatus) {
4507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            case PhoneUtils.CALL_STATUS_DIALED:
4517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (VDBG) log("placeCall: PhoneUtils.placeCall() succeeded for regular call '"
4527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                             + number + "'.");
4537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // TODO(OTASP): still need more cleanup to simplify the mApp.cdma*State objects:
4567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // - Rather than checking inCallUiState.inCallScreenMode, the
4577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //   code here could also check for
4587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //   app.getCdmaOtaInCallScreenUiState() returning NORMAL.
4597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // - But overall, app.inCallUiState.inCallScreenMode and
4607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //   app.cdmaOtaInCallScreenUiState.state are redundant.
4617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //   Combine them.
4627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                boolean voicemailUriSpecified = scheme != null && scheme.equals("voicemail");
4647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // Check for an obscure ECM-related scenario: If the phone
4657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // is currently in ECM (Emergency callback mode) and we
4667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // dial a non-emergency number, that automatically
4677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // *cancels* ECM.  So warn the user about it.
4687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // (See InCallScreen.showExitingECMDialog() for more info.)
4697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                boolean exitedEcm = false;
4707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (PhoneUtils.isPhoneInEcm(phone) && !isEmergencyNumber) {
4717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    Log.i(TAG, "About to exit ECM because of an outgoing non-emergency call");
4727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    exitedEcm = true;  // this will cause us to return EXITED_ECM from this method
4737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
4747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {
4767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    // Start the timer for 3 Way CallerInfo
4777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    if (mApp.cdmaPhoneCallState.getCurrentCallState()
4787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                            == CdmaPhoneCallState.PhoneCallState.THRWAY_ACTIVE) {
4797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        //Unmute for the second MO call
4807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        PhoneUtils.setMute(false);
4817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        // This is a "CDMA 3-way call", which means that you're dialing a
4837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        // 2nd outgoing call while a previous call is already in progress.
4847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        //
4857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        // Due to the limitations of CDMA this call doesn't actually go
4867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        // through the DIALING/ALERTING states, so we can't tell for sure
4877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        // when (or if) it's actually answered.  But we want to show
4887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        // *some* indication of what's going on in the UI, so we "fake it"
4897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        // by displaying the "Dialing" state for 3 seconds.
4907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        // Set the mThreeWayCallOrigStateDialing state to true
4927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        mApp.cdmaPhoneCallState.setThreeWayCallOrigState(true);
4937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
4947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        // Schedule the "Dialing" indication to be taken down in 3 seconds:
4957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        sendEmptyMessageDelayed(THREEWAY_CALLERINFO_DISPLAY_DONE,
4967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                                                THREEWAY_CALLERINFO_DISPLAY_TIME);
4977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    }
4987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
4997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // Success!
5017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (exitedEcm) {
5027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    return CallStatusCode.EXITED_ECM;
5037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                } else {
5047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                    return CallStatusCode.SUCCESS;
5057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                }
5067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            case PhoneUtils.CALL_STATUS_DIALED_MMI:
5087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                if (DBG) log("placeCall: specified number was an MMI code: '" + number + "'.");
5097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // The passed-in number was an MMI code, not a regular phone number!
5107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // This isn't really a failure; the Dialer may have deliberately
5117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // fired an ACTION_CALL intent to dial an MMI code, like for a
5127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // USSD call.
5137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //
5147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // Presumably an MMI_INITIATE message will come in shortly
5157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // (and we'll bring up the "MMI Started" dialog), or else
5167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // an MMI_COMPLETE will come in (which will take us to a
5177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // different Activity; see PhoneUtils.displayMMIComplete()).
5187d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                return CallStatusCode.DIALED_MMI;
5197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            case PhoneUtils.CALL_STATUS_FAILED:
5217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Log.w(TAG, "placeCall: PhoneUtils.placeCall() FAILED for number '"
5227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                      + number + "'.");
5237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // We couldn't successfully place the call; there was some
5247d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // failure in the telephony layer.
5257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // Log failed call.
5277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                mCallLogger.logCall(null /* callerInfo */, number, 0 /* presentation */,
5287d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        Calls.OUTGOING_TYPE, System.currentTimeMillis(), 0 /* duration */);
5297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                return CallStatusCode.CALL_FAILED;
5317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            default:
5337d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Log.wtf(TAG, "placeCall: unknown callStatus " + callStatus
5347d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                        + " from PhoneUtils.placeCall() for number '" + number + "'.");
5357d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                return CallStatusCode.SUCCESS;  // Try to continue anyway...
5367d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
5377d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
5387d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5397d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
5407d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Checks the current ServiceState to make sure it's OK
5417d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * to try making an outgoing call to the specified number.
5427d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
5437d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @return CallStatusCode.SUCCESS if it's OK to try calling the specified
5447d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *    number.  If not, like if the radio is powered off or we have no
5457d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *    signal, return one of the other CallStatusCode codes indicating what
5467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *    the problem is.
5477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
5487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private CallStatusCode checkIfOkToInitiateOutgoingCall(int state) {
5497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (VDBG) log("checkIfOkToInitiateOutgoingCall: ServiceState = " + state);
5507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        switch (state) {
5527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            case ServiceState.STATE_IN_SERVICE:
5537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // Normal operation.  It's OK to make outgoing calls.
5547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                return CallStatusCode.SUCCESS;
5557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            case ServiceState.STATE_POWER_OFF:
5577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // Radio is explictly powered off.
5587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                return CallStatusCode.POWER_OFF;
5597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            case ServiceState.STATE_EMERGENCY_ONLY:
5617d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // The phone is registered, but locked. Only emergency
5627d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // numbers are allowed.
5637d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // Note that as of Android 2.0 at least, the telephony layer
5647d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // does not actually use ServiceState.STATE_EMERGENCY_ONLY,
5657d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // mainly since there's no guarantee that the radio/RIL can
5667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // make this distinction.  So in practice the
5677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // CallStatusCode.EMERGENCY_ONLY state and the string
5687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // "incall_error_emergency_only" are totally unused.
5697d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                return CallStatusCode.EMERGENCY_ONLY;
5707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            case ServiceState.STATE_OUT_OF_SERVICE:
5727d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // No network connection.
5737d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                return CallStatusCode.OUT_OF_SERVICE;
5747d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5757d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            default:
5767d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                throw new IllegalStateException("Unexpected ServiceState: " + state);
5777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
5787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
5797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
5827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
5837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Handles the various error conditions that can occur when initiating
5847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * an outgoing call.
5857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
5867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Most error conditions are "handled" by simply displaying an error
58771028d0df4f699670dd7838011741c1cd9464061Yorke Lee     * message to the user.
5887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     *
5897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * @param status one of the CallStatusCode error codes.
5907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
5917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private void handleOutgoingCallError(CallStatusCode status) {
5927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (DBG) log("handleOutgoingCallError(): status = " + status);
59371028d0df4f699670dd7838011741c1cd9464061Yorke Lee        final Intent intent = new Intent(mApp, ErrorDialogActivity.class);
59471028d0df4f699670dd7838011741c1cd9464061Yorke Lee        int errorMessageId = -1;
5957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        switch (status) {
5967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            case SUCCESS:
5977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // This case shouldn't happen; you're only supposed to call
5987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // handleOutgoingCallError() if there was actually an error!
5997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Log.wtf(TAG, "handleOutgoingCallError: SUCCESS isn't an error");
6007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                break;
6017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
60271028d0df4f699670dd7838011741c1cd9464061Yorke Lee            case CALL_FAILED:
60371028d0df4f699670dd7838011741c1cd9464061Yorke Lee                // We couldn't successfully place the call; there was some
60471028d0df4f699670dd7838011741c1cd9464061Yorke Lee                // failure in the telephony layer.
60571028d0df4f699670dd7838011741c1cd9464061Yorke Lee                // TODO: Need UI spec for this failure case; for now just
60671028d0df4f699670dd7838011741c1cd9464061Yorke Lee                // show a generic error.
60771028d0df4f699670dd7838011741c1cd9464061Yorke Lee                errorMessageId = R.string.incall_error_call_failed;
6087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                break;
6097d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            case POWER_OFF:
6107d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // Radio is explictly powered off, presumably because the
6117d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // device is in airplane mode.
6127d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //
6137d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // TODO: For now this UI is ultra-simple: we simply display
6147d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // a message telling the user to turn off airplane mode.
6157d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // But it might be nicer for the dialog to offer the option
6167d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // to turn the radio on right there (and automatically retry
6177d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // the call once network registration is complete.)
61871028d0df4f699670dd7838011741c1cd9464061Yorke Lee                errorMessageId = R.string.incall_error_power_off;
6197d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                break;
6207d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            case EMERGENCY_ONLY:
6217d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // Only emergency numbers are allowed, but we tried to dial
6227d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // a non-emergency number.
6237d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // (This state is currently unused; see comments above.)
62471028d0df4f699670dd7838011741c1cd9464061Yorke Lee                errorMessageId = R.string.incall_error_emergency_only;
6257d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                break;
6267d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            case OUT_OF_SERVICE:
6277d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // No network connection.
62871028d0df4f699670dd7838011741c1cd9464061Yorke Lee                errorMessageId = R.string.incall_error_out_of_service;
6297d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                break;
6307d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            case NO_PHONE_NUMBER_SUPPLIED:
6317d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // The supplied Intent didn't contain a valid phone number.
6327d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // (This is rare and should only ever happen with broken
63371028d0df4f699670dd7838011741c1cd9464061Yorke Lee                // 3rd-party apps.) For now just show a generic error.
63471028d0df4f699670dd7838011741c1cd9464061Yorke Lee                errorMessageId = R.string.incall_error_no_phone_number_supplied;
63571028d0df4f699670dd7838011741c1cd9464061Yorke Lee                break;
63671028d0df4f699670dd7838011741c1cd9464061Yorke Lee
63771028d0df4f699670dd7838011741c1cd9464061Yorke Lee            case VOICEMAIL_NUMBER_MISSING:
63871028d0df4f699670dd7838011741c1cd9464061Yorke Lee                // Bring up the "Missing Voicemail Number" dialog, which
63971028d0df4f699670dd7838011741c1cd9464061Yorke Lee                // will ultimately take us to some other Activity (or else
64071028d0df4f699670dd7838011741c1cd9464061Yorke Lee                // just bail out of this activity.)
64171028d0df4f699670dd7838011741c1cd9464061Yorke Lee
64271028d0df4f699670dd7838011741c1cd9464061Yorke Lee                // Send a request to the InCallScreen to display the
64371028d0df4f699670dd7838011741c1cd9464061Yorke Lee                // "voicemail missing" dialog when it (the InCallScreen)
64471028d0df4f699670dd7838011741c1cd9464061Yorke Lee                // comes to the foreground.
64571028d0df4f699670dd7838011741c1cd9464061Yorke Lee                intent.putExtra(ErrorDialogActivity.SHOW_MISSING_VOICEMAIL_NO_DIALOG_EXTRA, true);
6467d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                break;
6477d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
6487d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            case DIALED_MMI:
6497d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // Our initial phone number was actually an MMI sequence.
6507d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // There's no real "error" here, but we do bring up the
6517d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // a Toast (as requested of the New UI paradigm).
6527d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //
6537d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // In-call MMIs do not trigger the normal MMI Initiate
6547d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // Notifications, so we should notify the user here.
6557d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // Otherwise, the code in PhoneUtils.java should handle
6567d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // user notifications in the form of Toasts or Dialogs.
6577d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                //
6587d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // TODO: Rather than launching a toast from here, it would
6597d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // be cleaner to just set a pending call status code here,
6607d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // and then let the InCallScreen display the toast...
661598dac56af25319ec4aa0f2a5d98adfc023d7ac4Yorke Lee                final Intent mmiIntent = new Intent(mApp, MMIDialogActivity.class);
662598dac56af25319ec4aa0f2a5d98adfc023d7ac4Yorke Lee                mmiIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
663598dac56af25319ec4aa0f2a5d98adfc023d7ac4Yorke Lee                        Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
664598dac56af25319ec4aa0f2a5d98adfc023d7ac4Yorke Lee                mApp.startActivity(mmiIntent);
66571028d0df4f699670dd7838011741c1cd9464061Yorke Lee                return;
6667d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            default:
6677d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                Log.wtf(TAG, "handleOutgoingCallError: unexpected status code " + status);
6687d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                // Show a generic "call failed" error.
66971028d0df4f699670dd7838011741c1cd9464061Yorke Lee                errorMessageId = R.string.incall_error_call_failed;
6707d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon                break;
6717d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
67271028d0df4f699670dd7838011741c1cd9464061Yorke Lee        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
67371028d0df4f699670dd7838011741c1cd9464061Yorke Lee        if (errorMessageId != -1) {
67471028d0df4f699670dd7838011741c1cd9464061Yorke Lee            intent.putExtra(ErrorDialogActivity.ERROR_MESSAGE_ID_EXTRA, errorMessageId);
67571028d0df4f699670dd7838011741c1cd9464061Yorke Lee        }
67671028d0df4f699670dd7838011741c1cd9464061Yorke Lee        mApp.startActivity(intent);
6777d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
6787d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
6797d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    /**
6807d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * Checks the current outgoing call to see if it's an OTASP call (the
6817d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * "activation" call used to provision CDMA devices).  If so, do any
6827d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     * necessary OTASP-specific setup before actually placing the call.
6837d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon     */
6847d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private void checkForOtaspCall(Intent intent) {
6857d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        if (OtaUtils.isOtaspCallIntent(intent)) {
6867d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            Log.i(TAG, "checkForOtaspCall: handling OTASP intent! " + intent);
6877d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
6887d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // ("OTASP-specific setup" basically means creating and initializing
6897d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // the OtaUtils instance.  Note that this setup needs to be here in
6907d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // the CallController.placeCall() sequence, *not* in
6917d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // OtaUtils.startInteractiveOtasp(), since it's also possible to
6927d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // start an OTASP call by manually dialing "*228" (in which case
6937d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            // OtaUtils.startInteractiveOtasp() never gets run at all.)
6947d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            OtaUtils.setupOtaspCall(intent);
6957d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        } else {
6967d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon            if (DBG) log("checkForOtaspCall: not an OTASP call.");
6977d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        }
6987d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
6997d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
7007d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
7017d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    //
7027d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    // Debugging
7037d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    //
7047d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon
7057d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    private static void log(String msg) {
7067d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon        Log.d(TAG, msg);
7077d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon    }
7087d4ddf6dc0d7c8158bac3a5dec7936e837e95bddSantos Cordon}
709