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