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