13426afaf85d33d454fad8d341a1a895fd7e21c10David Brown/* 23426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * Copyright (C) 2011 The Android Open Source Project 33426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * 43426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * Licensed under the Apache License, Version 2.0 (the "License"); 53426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * you may not use this file except in compliance with the License. 63426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * You may obtain a copy of the License at 73426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * 83426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * http://www.apache.org/licenses/LICENSE-2.0 93426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * 103426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * Unless required by applicable law or agreed to in writing, software 113426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * distributed under the License is distributed on an "AS IS" BASIS, 123426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * See the License for the specific language governing permissions and 143426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * limitations under the License. 153426afaf85d33d454fad8d341a1a895fd7e21c10David Brown */ 163426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 173426afaf85d33d454fad8d341a1a895fd7e21c10David Brownpackage com.android.phone; 183426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 193426afaf85d33d454fad8d341a1a895fd7e21c10David Brownimport com.android.internal.telephony.CallManager; 203426afaf85d33d454fad8d341a1a895fd7e21c10David Brownimport com.android.internal.telephony.Connection; 213426afaf85d33d454fad8d341a1a895fd7e21c10David Brownimport com.android.internal.telephony.Phone; 223426afaf85d33d454fad8d341a1a895fd7e21c10David Brownimport com.android.phone.Constants.CallStatusCode; 233426afaf85d33d454fad8d341a1a895fd7e21c10David Brownimport com.android.phone.InCallUiState.ProgressIndicationType; 243426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 253426afaf85d33d454fad8d341a1a895fd7e21c10David Brownimport android.content.Context; 263426afaf85d33d454fad8d341a1a895fd7e21c10David Brownimport android.content.Intent; 273426afaf85d33d454fad8d341a1a895fd7e21c10David Brownimport android.os.AsyncResult; 283426afaf85d33d454fad8d341a1a895fd7e21c10David Brownimport android.os.Handler; 293426afaf85d33d454fad8d341a1a895fd7e21c10David Brownimport android.os.Message; 303426afaf85d33d454fad8d341a1a895fd7e21c10David Brownimport android.os.PowerManager; 313426afaf85d33d454fad8d341a1a895fd7e21c10David Brownimport android.provider.Settings; 323426afaf85d33d454fad8d341a1a895fd7e21c10David Brownimport android.telephony.ServiceState; 333426afaf85d33d454fad8d341a1a895fd7e21c10David Brownimport android.util.Log; 343426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 353426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 363426afaf85d33d454fad8d341a1a895fd7e21c10David Brown/** 373426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * Helper class for the {@link CallController} that implements special 383426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * behavior related to emergency calls. Specifically, this class handles 393426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * the case of the user trying to dial an emergency number while the radio 403426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * is off (i.e. the device is in airplane mode), by forcibly turning the 413426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * radio back on, waiting for it to come up, and then retrying the 423426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * emergency call. 433426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * 443426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * This class is instantiated lazily (the first time the user attempts to 453426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * make an emergency call from airplane mode) by the the 463426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * {@link CallController} singleton. 473426afaf85d33d454fad8d341a1a895fd7e21c10David Brown */ 483426afaf85d33d454fad8d341a1a895fd7e21c10David Brownpublic class EmergencyCallHelper extends Handler { 493426afaf85d33d454fad8d341a1a895fd7e21c10David Brown private static final String TAG = "EmergencyCallHelper"; 503426afaf85d33d454fad8d341a1a895fd7e21c10David Brown private static final boolean DBG = true; 513426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 523426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // Number of times to retry the call, and time between retry attempts. 533426afaf85d33d454fad8d341a1a895fd7e21c10David Brown public static final int MAX_NUM_RETRIES = 6; 543426afaf85d33d454fad8d341a1a895fd7e21c10David Brown public static final long TIME_BETWEEN_RETRIES = 5000; // msec 553426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 563426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // Timeout used with our wake lock (just as a safety valve to make 573426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // sure we don't hold it forever). 583426afaf85d33d454fad8d341a1a895fd7e21c10David Brown public static final long WAKE_LOCK_TIMEOUT = 5 * 60 * 1000; // 5 minutes in msec 593426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 603426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // Handler message codes; see handleMessage() 613426afaf85d33d454fad8d341a1a895fd7e21c10David Brown private static final int START_SEQUENCE = 1; 623426afaf85d33d454fad8d341a1a895fd7e21c10David Brown private static final int SERVICE_STATE_CHANGED = 2; 633426afaf85d33d454fad8d341a1a895fd7e21c10David Brown private static final int DISCONNECT = 3; 643426afaf85d33d454fad8d341a1a895fd7e21c10David Brown private static final int RETRY_TIMEOUT = 4; 653426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 663426afaf85d33d454fad8d341a1a895fd7e21c10David Brown private CallController mCallController; 673426afaf85d33d454fad8d341a1a895fd7e21c10David Brown private PhoneApp mApp; 683426afaf85d33d454fad8d341a1a895fd7e21c10David Brown private CallManager mCM; 693426afaf85d33d454fad8d341a1a895fd7e21c10David Brown private Phone mPhone; 703426afaf85d33d454fad8d341a1a895fd7e21c10David Brown private String mNumber; // The emergency number we're trying to dial 713426afaf85d33d454fad8d341a1a895fd7e21c10David Brown private int mNumRetriesSoFar; 723426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 733426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // Wake lock we hold while running the whole sequence 743426afaf85d33d454fad8d341a1a895fd7e21c10David Brown private PowerManager.WakeLock mPartialWakeLock; 753426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 763426afaf85d33d454fad8d341a1a895fd7e21c10David Brown public EmergencyCallHelper(CallController callController) { 773426afaf85d33d454fad8d341a1a895fd7e21c10David Brown if (DBG) log("EmergencyCallHelper constructor..."); 783426afaf85d33d454fad8d341a1a895fd7e21c10David Brown mCallController = callController; 793426afaf85d33d454fad8d341a1a895fd7e21c10David Brown mApp = PhoneApp.getInstance(); 803426afaf85d33d454fad8d341a1a895fd7e21c10David Brown mCM = mApp.mCM; 813426afaf85d33d454fad8d341a1a895fd7e21c10David Brown } 823426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 833426afaf85d33d454fad8d341a1a895fd7e21c10David Brown @Override 843426afaf85d33d454fad8d341a1a895fd7e21c10David Brown public void handleMessage(Message msg) { 853426afaf85d33d454fad8d341a1a895fd7e21c10David Brown switch (msg.what) { 863426afaf85d33d454fad8d341a1a895fd7e21c10David Brown case START_SEQUENCE: 873426afaf85d33d454fad8d341a1a895fd7e21c10David Brown startSequenceInternal(msg); 883426afaf85d33d454fad8d341a1a895fd7e21c10David Brown break; 893426afaf85d33d454fad8d341a1a895fd7e21c10David Brown case SERVICE_STATE_CHANGED: 903426afaf85d33d454fad8d341a1a895fd7e21c10David Brown onServiceStateChanged(msg); 913426afaf85d33d454fad8d341a1a895fd7e21c10David Brown break; 923426afaf85d33d454fad8d341a1a895fd7e21c10David Brown case DISCONNECT: 933426afaf85d33d454fad8d341a1a895fd7e21c10David Brown onDisconnect(msg); 943426afaf85d33d454fad8d341a1a895fd7e21c10David Brown break; 953426afaf85d33d454fad8d341a1a895fd7e21c10David Brown case RETRY_TIMEOUT: 963426afaf85d33d454fad8d341a1a895fd7e21c10David Brown onRetryTimeout(); 973426afaf85d33d454fad8d341a1a895fd7e21c10David Brown break; 983426afaf85d33d454fad8d341a1a895fd7e21c10David Brown default: 993426afaf85d33d454fad8d341a1a895fd7e21c10David Brown Log.wtf(TAG, "handleMessage: unexpected message: " + msg); 1003426afaf85d33d454fad8d341a1a895fd7e21c10David Brown break; 1013426afaf85d33d454fad8d341a1a895fd7e21c10David Brown } 1023426afaf85d33d454fad8d341a1a895fd7e21c10David Brown } 1033426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 1043426afaf85d33d454fad8d341a1a895fd7e21c10David Brown /** 1053426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * Starts the "emergency call from airplane mode" sequence. 1063426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * 1073426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * This is the (single) external API of the EmergencyCallHelper class. 1083426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * This method is called from the CallController placeCall() sequence 1093426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * if the user dials a valid emergency number, but the radio is 1103426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * powered-off (presumably due to airplane mode.) 1113426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * 1123426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * This method kicks off the following sequence: 1133426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * - Power on the radio 1143426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * - Listen for the service state change event telling us the radio has come up 1153426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * - Then launch the emergency call 1163426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * - Retry if the call fails with an OUT_OF_SERVICE error 1173426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * - Retry if we've gone 5 seconds without any response from the radio 1183426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * - Finally, clean up any leftover state (progress UI, wake locks, etc.) 1193426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * 1203426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * This method is safe to call from any thread, since it simply posts 1213426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * a message to the EmergencyCallHelper's handler (thus ensuring that 1223426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * the rest of the sequence is entirely serialized, and runs only on 1233426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * the handler thread.) 1243426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * 1253426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * This method does *not* force the in-call UI to come up; our caller 1263426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * is responsible for doing that (presumably by calling 1273426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * PhoneApp.displayCallScreen().) 1283426afaf85d33d454fad8d341a1a895fd7e21c10David Brown */ 1293426afaf85d33d454fad8d341a1a895fd7e21c10David Brown public void startEmergencyCallFromAirplaneModeSequence(String number) { 1303426afaf85d33d454fad8d341a1a895fd7e21c10David Brown if (DBG) log("startEmergencyCallFromAirplaneModeSequence('" + number + "')..."); 1313426afaf85d33d454fad8d341a1a895fd7e21c10David Brown Message msg = obtainMessage(START_SEQUENCE, number); 1323426afaf85d33d454fad8d341a1a895fd7e21c10David Brown sendMessage(msg); 1333426afaf85d33d454fad8d341a1a895fd7e21c10David Brown } 1343426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 1353426afaf85d33d454fad8d341a1a895fd7e21c10David Brown /** 1363426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * Actual implementation of startEmergencyCallFromAirplaneModeSequence(), 1373426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * guaranteed to run on the handler thread. 1383426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * @see startEmergencyCallFromAirplaneModeSequence() 1393426afaf85d33d454fad8d341a1a895fd7e21c10David Brown */ 1403426afaf85d33d454fad8d341a1a895fd7e21c10David Brown private void startSequenceInternal(Message msg) { 1413426afaf85d33d454fad8d341a1a895fd7e21c10David Brown if (DBG) log("startSequenceInternal(): msg = " + msg); 1423426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 1433426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // First of all, clean up any state (including mPartialWakeLock!) 1443426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // left over from a prior emergency call sequence. 1453426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // This ensures that we'll behave sanely if another 1463426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // startEmergencyCallFromAirplaneModeSequence() comes in while 1473426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // we're already in the middle of the sequence. 1483426afaf85d33d454fad8d341a1a895fd7e21c10David Brown cleanup(); 1493426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 1503426afaf85d33d454fad8d341a1a895fd7e21c10David Brown mNumber = (String) msg.obj; 1513426afaf85d33d454fad8d341a1a895fd7e21c10David Brown if (DBG) log("- startSequenceInternal: Got mNumber: '" + mNumber + "'"); 1523426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 1533426afaf85d33d454fad8d341a1a895fd7e21c10David Brown mNumRetriesSoFar = 0; 1543426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 1553426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // Reset mPhone to whatever the current default phone is right now. 1563426afaf85d33d454fad8d341a1a895fd7e21c10David Brown mPhone = mApp.mCM.getDefaultPhone(); 1573426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 1583426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // Wake lock to make sure the processor doesn't go to sleep midway 1593426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // through the emergency call sequence. 1603426afaf85d33d454fad8d341a1a895fd7e21c10David Brown PowerManager pm = (PowerManager) mApp.getSystemService(Context.POWER_SERVICE); 1613426afaf85d33d454fad8d341a1a895fd7e21c10David Brown mPartialWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); 1623426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // Acquire with a timeout, just to be sure we won't hold the wake 1633426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // lock forever even if a logic bug (in this class) causes us to 1643426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // somehow never call cleanup(). 1653426afaf85d33d454fad8d341a1a895fd7e21c10David Brown if (DBG) log("- startSequenceInternal: acquiring wake lock"); 1663426afaf85d33d454fad8d341a1a895fd7e21c10David Brown mPartialWakeLock.acquire(WAKE_LOCK_TIMEOUT); 1673426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 1683426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // No need to check the current service state here, since the only 1693426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // reason the CallController would call this method in the first 1703426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // place is if the radio is powered-off. 1713426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // 1723426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // So just go ahead and turn the radio on. 1733426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 1743426afaf85d33d454fad8d341a1a895fd7e21c10David Brown powerOnRadio(); // We'll get an onServiceStateChanged() callback 1753426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // when the radio successfully comes up. 1763426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 1773426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // Next step: when the SERVICE_STATE_CHANGED event comes in, 1783426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // we'll retry the call; see placeEmergencyCall(); 1793426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // But also, just in case, start a timer to make sure we'll retry 1803426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // the call even if the SERVICE_STATE_CHANGED event never comes in 1813426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // for some reason. 1823426afaf85d33d454fad8d341a1a895fd7e21c10David Brown startRetryTimer(); 1833426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 1843426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // And finally, let the in-call UI know that we need to 1853426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // display the "Turning on radio..." progress indication. 1863426afaf85d33d454fad8d341a1a895fd7e21c10David Brown mApp.inCallUiState.setProgressIndication(ProgressIndicationType.TURNING_ON_RADIO); 1873426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 1883426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // (Our caller is responsible for calling mApp.displayCallScreen().) 1893426afaf85d33d454fad8d341a1a895fd7e21c10David Brown } 1903426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 1913426afaf85d33d454fad8d341a1a895fd7e21c10David Brown /** 1923426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * Handles the SERVICE_STATE_CHANGED event. 1933426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * 1943426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * (Normally this event tells us that the radio has finally come 1953426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * up. In that case, it's now safe to actually place the 1963426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * emergency call.) 1973426afaf85d33d454fad8d341a1a895fd7e21c10David Brown */ 1983426afaf85d33d454fad8d341a1a895fd7e21c10David Brown private void onServiceStateChanged(Message msg) { 1993426afaf85d33d454fad8d341a1a895fd7e21c10David Brown ServiceState state = (ServiceState) ((AsyncResult) msg.obj).result; 2003426afaf85d33d454fad8d341a1a895fd7e21c10David Brown if (DBG) log("onServiceStateChanged()... new state = " + state); 2013426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 2023426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // Possible service states: 2033426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // - STATE_IN_SERVICE // Normal operation 2043426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // - STATE_OUT_OF_SERVICE // Still searching for an operator to register to, 2053426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // // or no radio signal 2063426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // - STATE_EMERGENCY_ONLY // Phone is locked; only emergency numbers are allowed 2073426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // - STATE_POWER_OFF // Radio is explicitly powered off (airplane mode) 2083426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 2093426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // Once we reach either STATE_IN_SERVICE or STATE_EMERGENCY_ONLY, 2103426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // it's finally OK to place the emergency call. 2113426afaf85d33d454fad8d341a1a895fd7e21c10David Brown boolean okToCall = (state.getState() == ServiceState.STATE_IN_SERVICE) 2123426afaf85d33d454fad8d341a1a895fd7e21c10David Brown || (state.getState() == ServiceState.STATE_EMERGENCY_ONLY); 2133426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 2143426afaf85d33d454fad8d341a1a895fd7e21c10David Brown if (okToCall) { 2153426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // Woo hoo! It's OK to actually place the call. 2163426afaf85d33d454fad8d341a1a895fd7e21c10David Brown if (DBG) log("onServiceStateChanged: ok to call!"); 2173426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 2183426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // Deregister for the service state change events. 2193426afaf85d33d454fad8d341a1a895fd7e21c10David Brown unregisterForServiceStateChanged(); 2203426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 2213426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // Take down the "Turning on radio..." indication. 2223426afaf85d33d454fad8d341a1a895fd7e21c10David Brown mApp.inCallUiState.clearProgressIndication(); 2233426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 2243426afaf85d33d454fad8d341a1a895fd7e21c10David Brown placeEmergencyCall(); 2253426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 2263426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // The in-call UI is probably still up at this point, 2273426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // but make sure of that: 2283426afaf85d33d454fad8d341a1a895fd7e21c10David Brown mApp.displayCallScreen(); 2293426afaf85d33d454fad8d341a1a895fd7e21c10David Brown } else { 2303426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // The service state changed, but we're still not ready to call yet. 2313426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // (This probably was the transition from STATE_POWER_OFF to 2323426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // STATE_OUT_OF_SERVICE, which happens immediately after powering-on 2333426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // the radio.) 2343426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // 2353426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // So just keep waiting; we'll probably get to either 2363426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // STATE_IN_SERVICE or STATE_EMERGENCY_ONLY very shortly. 2373426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // (Or even if that doesn't happen, we'll at least do another retry 2383426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // when the RETRY_TIMEOUT event fires.) 2393426afaf85d33d454fad8d341a1a895fd7e21c10David Brown if (DBG) log("onServiceStateChanged: not ready to call yet, keep waiting..."); 2403426afaf85d33d454fad8d341a1a895fd7e21c10David Brown } 2413426afaf85d33d454fad8d341a1a895fd7e21c10David Brown } 2423426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 2433426afaf85d33d454fad8d341a1a895fd7e21c10David Brown /** 2443426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * Handles a DISCONNECT event from the telephony layer. 2453426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * 2463426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * Even after we successfully place an emergency call (after powering 2473426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * on the radio), it's still possible for the call to fail with the 2483426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * disconnect cause OUT_OF_SERVICE. If so, schedule a retry. 2493426afaf85d33d454fad8d341a1a895fd7e21c10David Brown */ 2503426afaf85d33d454fad8d341a1a895fd7e21c10David Brown private void onDisconnect(Message msg) { 2513426afaf85d33d454fad8d341a1a895fd7e21c10David Brown Connection conn = (Connection) ((AsyncResult) msg.obj).result; 2523426afaf85d33d454fad8d341a1a895fd7e21c10David Brown Connection.DisconnectCause cause = conn.getDisconnectCause(); 2533426afaf85d33d454fad8d341a1a895fd7e21c10David Brown if (DBG) log("onDisconnect: connection '" + conn 2543426afaf85d33d454fad8d341a1a895fd7e21c10David Brown + "', addr '" + conn.getAddress() + "', cause = " + cause); 2553426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 2563426afaf85d33d454fad8d341a1a895fd7e21c10David Brown if (cause == Connection.DisconnectCause.OUT_OF_SERVICE) { 2573426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // Wait a bit more and try again (or just bail out totally if 2583426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // we've had too many failures.) 2593426afaf85d33d454fad8d341a1a895fd7e21c10David Brown if (DBG) log("- onDisconnect: OUT_OF_SERVICE, need to retry..."); 2603426afaf85d33d454fad8d341a1a895fd7e21c10David Brown scheduleRetryOrBailOut(); 2613426afaf85d33d454fad8d341a1a895fd7e21c10David Brown } else { 2623426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // Any other disconnect cause means we're done. 2633426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // Either the emergency call succeeded *and* ended normally, 2643426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // or else there was some error that we can't retry. In either 2653426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // case, just clean up our internal state.) 2663426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 2673426afaf85d33d454fad8d341a1a895fd7e21c10David Brown if (DBG) log("==> Disconnect event; clean up..."); 2683426afaf85d33d454fad8d341a1a895fd7e21c10David Brown cleanup(); 2693426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 2703426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // Nothing else to do here. If the InCallScreen was visible, 2713426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // it would have received this disconnect event too (so it'll 2723426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // show the "Call ended" state and finish itself without any 2733426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // help from us.) 2743426afaf85d33d454fad8d341a1a895fd7e21c10David Brown } 2753426afaf85d33d454fad8d341a1a895fd7e21c10David Brown } 2763426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 2773426afaf85d33d454fad8d341a1a895fd7e21c10David Brown /** 2783426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * Handles the retry timer expiring. 2793426afaf85d33d454fad8d341a1a895fd7e21c10David Brown */ 2803426afaf85d33d454fad8d341a1a895fd7e21c10David Brown private void onRetryTimeout() { 2813426afaf85d33d454fad8d341a1a895fd7e21c10David Brown Phone.State phoneState = mCM.getState(); 2823426afaf85d33d454fad8d341a1a895fd7e21c10David Brown int serviceState = mPhone.getServiceState().getState(); 2833426afaf85d33d454fad8d341a1a895fd7e21c10David Brown if (DBG) log("onRetryTimeout(): phone state " + phoneState 2843426afaf85d33d454fad8d341a1a895fd7e21c10David Brown + ", service state " + serviceState 2853426afaf85d33d454fad8d341a1a895fd7e21c10David Brown + ", mNumRetriesSoFar = " + mNumRetriesSoFar); 2863426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 2873426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // - If we're actually in a call, we've succeeded. 2883426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // 2893426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // - Otherwise, if the radio is now on, that means we successfully got 2903426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // out of airplane mode but somehow didn't get the service state 2913426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // change event. In that case, try to place the call. 2923426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // 2933426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // - If the radio is still powered off, try powering it on again. 2943426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 2953426afaf85d33d454fad8d341a1a895fd7e21c10David Brown if (phoneState == Phone.State.OFFHOOK) { 2963426afaf85d33d454fad8d341a1a895fd7e21c10David Brown if (DBG) log("- onRetryTimeout: Call is active! Cleaning up..."); 2973426afaf85d33d454fad8d341a1a895fd7e21c10David Brown cleanup(); 2983426afaf85d33d454fad8d341a1a895fd7e21c10David Brown return; 2993426afaf85d33d454fad8d341a1a895fd7e21c10David Brown } 3003426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 3013426afaf85d33d454fad8d341a1a895fd7e21c10David Brown if (serviceState != ServiceState.STATE_POWER_OFF) { 3023426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // Woo hoo -- we successfully got out of airplane mode. 3033426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 3043426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // Deregister for the service state change events; we don't need 3053426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // these any more now that the radio is powered-on. 3063426afaf85d33d454fad8d341a1a895fd7e21c10David Brown unregisterForServiceStateChanged(); 3073426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 3083426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // Take down the "Turning on radio..." indication. 3093426afaf85d33d454fad8d341a1a895fd7e21c10David Brown mApp.inCallUiState.clearProgressIndication(); 3103426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 3113426afaf85d33d454fad8d341a1a895fd7e21c10David Brown placeEmergencyCall(); // If the call fails, placeEmergencyCall() 3123426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // will schedule a retry. 3133426afaf85d33d454fad8d341a1a895fd7e21c10David Brown } else { 3143426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // Uh oh; we've waited the full TIME_BETWEEN_RETRIES and the 3153426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // radio is still not powered-on. Try again... 3163426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 3173426afaf85d33d454fad8d341a1a895fd7e21c10David Brown if (DBG) log("- Trying (again) to turn on the radio..."); 3183426afaf85d33d454fad8d341a1a895fd7e21c10David Brown powerOnRadio(); // Again, we'll (hopefully) get an onServiceStateChanged() 3193426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // callback when the radio successfully comes up. 3203426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 3213426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // ...and also set a fresh retry timer (or just bail out 3223426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // totally if we've had too many failures.) 3233426afaf85d33d454fad8d341a1a895fd7e21c10David Brown scheduleRetryOrBailOut(); 3243426afaf85d33d454fad8d341a1a895fd7e21c10David Brown } 3253426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 3263426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // Finally, the in-call UI is probably still up at this point, 3273426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // but make sure of that: 3283426afaf85d33d454fad8d341a1a895fd7e21c10David Brown mApp.displayCallScreen(); 3293426afaf85d33d454fad8d341a1a895fd7e21c10David Brown } 3303426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 3313426afaf85d33d454fad8d341a1a895fd7e21c10David Brown /** 3323426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * Attempt to power on the radio (i.e. take the device out 3333426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * of airplane mode.) 3343426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * 3353426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * Additionally, start listening for service state changes; 3363426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * we'll eventually get an onServiceStateChanged() callback 3373426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * when the radio successfully comes up. 3383426afaf85d33d454fad8d341a1a895fd7e21c10David Brown */ 3393426afaf85d33d454fad8d341a1a895fd7e21c10David Brown private void powerOnRadio() { 3403426afaf85d33d454fad8d341a1a895fd7e21c10David Brown if (DBG) log("- powerOnRadio()..."); 3413426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 3423426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // We're about to turn on the radio, so arrange to be notified 3433426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // when the sequence is complete. 3443426afaf85d33d454fad8d341a1a895fd7e21c10David Brown registerForServiceStateChanged(); 3453426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 3463426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // If airplane mode is on, we turn it off the same way that the 3473426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // Settings activity turns it off. 3483426afaf85d33d454fad8d341a1a895fd7e21c10David Brown if (Settings.System.getInt(mApp.getContentResolver(), 3493426afaf85d33d454fad8d341a1a895fd7e21c10David Brown Settings.System.AIRPLANE_MODE_ON, 0) > 0) { 3503426afaf85d33d454fad8d341a1a895fd7e21c10David Brown if (DBG) log("==> Turning off airplane mode..."); 3513426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 3523426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // Change the system setting 3533426afaf85d33d454fad8d341a1a895fd7e21c10David Brown Settings.System.putInt(mApp.getContentResolver(), 3543426afaf85d33d454fad8d341a1a895fd7e21c10David Brown Settings.System.AIRPLANE_MODE_ON, 0); 3553426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 3563426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // Post the intent 3573426afaf85d33d454fad8d341a1a895fd7e21c10David Brown Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); 3583426afaf85d33d454fad8d341a1a895fd7e21c10David Brown intent.putExtra("state", false); 3593426afaf85d33d454fad8d341a1a895fd7e21c10David Brown mApp.sendBroadcast(intent); 3603426afaf85d33d454fad8d341a1a895fd7e21c10David Brown } else { 3613426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // Otherwise, for some strange reason the radio is off 3623426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // (even though the Settings database doesn't think we're 3633426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // in airplane mode.) In this case just turn the radio 3643426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // back on. 3653426afaf85d33d454fad8d341a1a895fd7e21c10David Brown if (DBG) log("==> (Apparently) not in airplane mode; manually powering radio on..."); 3663426afaf85d33d454fad8d341a1a895fd7e21c10David Brown mPhone.setRadioPower(true); 3673426afaf85d33d454fad8d341a1a895fd7e21c10David Brown } 3683426afaf85d33d454fad8d341a1a895fd7e21c10David Brown } 3693426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 3703426afaf85d33d454fad8d341a1a895fd7e21c10David Brown /** 3713426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * Actually initiate the outgoing emergency call. 3723426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * (We do this once the radio has successfully been powered-up.) 3733426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * 3743426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * If the call succeeds, we're done. 3753426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * If the call fails, schedule a retry of the whole sequence. 3763426afaf85d33d454fad8d341a1a895fd7e21c10David Brown */ 3773426afaf85d33d454fad8d341a1a895fd7e21c10David Brown private void placeEmergencyCall() { 3783426afaf85d33d454fad8d341a1a895fd7e21c10David Brown if (DBG) log("placeEmergencyCall()..."); 3793426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 3803426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // Place an outgoing call to mNumber. 3813426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // Note we call PhoneUtils.placeCall() directly; we don't want any 3823426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // of the behavior from CallController.placeCallInternal() here. 3833426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // (Specifically, we don't want to start the "emergency call from 3843426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // airplane mode" sequence from the beginning again!) 3853426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 3863426afaf85d33d454fad8d341a1a895fd7e21c10David Brown registerForDisconnect(); // Get notified when this call disconnects 3873426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 3883426afaf85d33d454fad8d341a1a895fd7e21c10David Brown if (DBG) log("- placing call to '" + mNumber + "'..."); 3893426afaf85d33d454fad8d341a1a895fd7e21c10David Brown int callStatus = PhoneUtils.placeCall(mApp, 3903426afaf85d33d454fad8d341a1a895fd7e21c10David Brown mPhone, 3913426afaf85d33d454fad8d341a1a895fd7e21c10David Brown mNumber, 3923426afaf85d33d454fad8d341a1a895fd7e21c10David Brown null, // contactUri 3933426afaf85d33d454fad8d341a1a895fd7e21c10David Brown true, // isEmergencyCall 3943426afaf85d33d454fad8d341a1a895fd7e21c10David Brown null); // gatewayUri 3953426afaf85d33d454fad8d341a1a895fd7e21c10David Brown if (DBG) log("- PhoneUtils.placeCall() returned status = " + callStatus); 3963426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 3973426afaf85d33d454fad8d341a1a895fd7e21c10David Brown boolean success; 3983426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // Note PhoneUtils.placeCall() returns one of the CALL_STATUS_* 3993426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // constants, not a CallStatusCode enum value. 4003426afaf85d33d454fad8d341a1a895fd7e21c10David Brown switch (callStatus) { 4013426afaf85d33d454fad8d341a1a895fd7e21c10David Brown case PhoneUtils.CALL_STATUS_DIALED: 4023426afaf85d33d454fad8d341a1a895fd7e21c10David Brown success = true; 4033426afaf85d33d454fad8d341a1a895fd7e21c10David Brown break; 4043426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 4053426afaf85d33d454fad8d341a1a895fd7e21c10David Brown case PhoneUtils.CALL_STATUS_DIALED_MMI: 4063426afaf85d33d454fad8d341a1a895fd7e21c10David Brown case PhoneUtils.CALL_STATUS_FAILED: 4073426afaf85d33d454fad8d341a1a895fd7e21c10David Brown default: 4083426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // Anything else is a failure, and we'll need to retry. 4093426afaf85d33d454fad8d341a1a895fd7e21c10David Brown Log.w(TAG, "placeEmergencyCall(): placeCall() failed: callStatus = " + callStatus); 4103426afaf85d33d454fad8d341a1a895fd7e21c10David Brown success = false; 4113426afaf85d33d454fad8d341a1a895fd7e21c10David Brown break; 4123426afaf85d33d454fad8d341a1a895fd7e21c10David Brown } 4133426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 4143426afaf85d33d454fad8d341a1a895fd7e21c10David Brown if (success) { 4153426afaf85d33d454fad8d341a1a895fd7e21c10David Brown if (DBG) log("==> Success from PhoneUtils.placeCall()!"); 4163426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // Ok, the emergency call is (hopefully) under way. 4173426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 4183426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // We're not done yet, though, so don't call cleanup() here. 4193426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // (It's still possible that this call will fail, and disconnect 4203426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // with cause==OUT_OF_SERVICE. If so, that will trigger a retry 4213426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // from the onDisconnect() method.) 4223426afaf85d33d454fad8d341a1a895fd7e21c10David Brown } else { 4233426afaf85d33d454fad8d341a1a895fd7e21c10David Brown if (DBG) log("==> Failure."); 4243426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // Wait a bit more and try again (or just bail out totally if 4253426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // we've had too many failures.) 4263426afaf85d33d454fad8d341a1a895fd7e21c10David Brown scheduleRetryOrBailOut(); 4273426afaf85d33d454fad8d341a1a895fd7e21c10David Brown } 4283426afaf85d33d454fad8d341a1a895fd7e21c10David Brown } 4293426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 4303426afaf85d33d454fad8d341a1a895fd7e21c10David Brown /** 4313426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * Schedules a retry in response to some failure (either the radio 4323426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * failing to power on, or a failure when trying to place the call.) 4333426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * Or, if we've hit the retry limit, bail out of this whole sequence 4343426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * and display a failure message to the user. 4353426afaf85d33d454fad8d341a1a895fd7e21c10David Brown */ 4363426afaf85d33d454fad8d341a1a895fd7e21c10David Brown private void scheduleRetryOrBailOut() { 4373426afaf85d33d454fad8d341a1a895fd7e21c10David Brown mNumRetriesSoFar++; 4383426afaf85d33d454fad8d341a1a895fd7e21c10David Brown if (DBG) log("scheduleRetryOrBailOut()... mNumRetriesSoFar is now " + mNumRetriesSoFar); 4393426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 4403426afaf85d33d454fad8d341a1a895fd7e21c10David Brown if (mNumRetriesSoFar > MAX_NUM_RETRIES) { 4413426afaf85d33d454fad8d341a1a895fd7e21c10David Brown Log.w(TAG, "scheduleRetryOrBailOut: hit MAX_NUM_RETRIES; giving up..."); 4423426afaf85d33d454fad8d341a1a895fd7e21c10David Brown cleanup(); 4433426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // ...and have the InCallScreen display a generic failure 4443426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // message. 4453426afaf85d33d454fad8d341a1a895fd7e21c10David Brown mApp.inCallUiState.setPendingCallStatusCode(CallStatusCode.CALL_FAILED); 4463426afaf85d33d454fad8d341a1a895fd7e21c10David Brown } else { 4473426afaf85d33d454fad8d341a1a895fd7e21c10David Brown if (DBG) log("- Scheduling another retry..."); 4483426afaf85d33d454fad8d341a1a895fd7e21c10David Brown startRetryTimer(); 4493426afaf85d33d454fad8d341a1a895fd7e21c10David Brown mApp.inCallUiState.setProgressIndication(ProgressIndicationType.RETRYING); 4503426afaf85d33d454fad8d341a1a895fd7e21c10David Brown } 4513426afaf85d33d454fad8d341a1a895fd7e21c10David Brown } 4523426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 4533426afaf85d33d454fad8d341a1a895fd7e21c10David Brown /** 4543426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * Clean up when done with the whole sequence: either after 4553426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * successfully placing *and* ending the emergency call, or after 4563426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * bailing out because of too many failures. 4573426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * 4583426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * The exact cleanup steps are: 4593426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * - Take down any progress UI (and also ask the in-call UI to refresh itself, 4603426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * if it's still visible) 4613426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * - Double-check that we're not still registered for any telephony events 4623426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * - Clean up any extraneous handler messages (like retry timeouts) still in the queue 4633426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * - Make sure we're not still holding any wake locks 4643426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * 4653426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * Basically this method guarantees that there will be no more 4663426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * activity from the EmergencyCallHelper until the CallController 4673426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * kicks off the whole sequence again with another call to 4683426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * startEmergencyCallFromAirplaneModeSequence(). 4693426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * 4703426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * Note we don't call this method simply after a successful call to 4713426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * placeCall(), since it's still possible the call will disconnect 4723426afaf85d33d454fad8d341a1a895fd7e21c10David Brown * very quickly with an OUT_OF_SERVICE error. 4733426afaf85d33d454fad8d341a1a895fd7e21c10David Brown */ 4743426afaf85d33d454fad8d341a1a895fd7e21c10David Brown private void cleanup() { 4753426afaf85d33d454fad8d341a1a895fd7e21c10David Brown if (DBG) log("cleanup()..."); 4763426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 4773426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // Take down the "Turning on radio..." indication. 4783426afaf85d33d454fad8d341a1a895fd7e21c10David Brown mApp.inCallUiState.clearProgressIndication(); 4793426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 4803426afaf85d33d454fad8d341a1a895fd7e21c10David Brown unregisterForServiceStateChanged(); 4813426afaf85d33d454fad8d341a1a895fd7e21c10David Brown unregisterForDisconnect(); 4823426afaf85d33d454fad8d341a1a895fd7e21c10David Brown cancelRetryTimer(); 4833426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 4843426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // Release / clean up the wake lock 4853426afaf85d33d454fad8d341a1a895fd7e21c10David Brown if (mPartialWakeLock != null) { 4863426afaf85d33d454fad8d341a1a895fd7e21c10David Brown if (mPartialWakeLock.isHeld()) { 4873426afaf85d33d454fad8d341a1a895fd7e21c10David Brown if (DBG) log("- releasing wake lock"); 4883426afaf85d33d454fad8d341a1a895fd7e21c10David Brown mPartialWakeLock.release(); 4893426afaf85d33d454fad8d341a1a895fd7e21c10David Brown } 4903426afaf85d33d454fad8d341a1a895fd7e21c10David Brown mPartialWakeLock = null; 4913426afaf85d33d454fad8d341a1a895fd7e21c10David Brown } 4923426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 4933426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // And finally, ask the in-call UI to refresh itself (to clean up the 4943426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // progress indication if necessary), if it's currently visible. 4953426afaf85d33d454fad8d341a1a895fd7e21c10David Brown mApp.updateInCallScreen(); 4963426afaf85d33d454fad8d341a1a895fd7e21c10David Brown } 4973426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 4983426afaf85d33d454fad8d341a1a895fd7e21c10David Brown private void startRetryTimer() { 4993426afaf85d33d454fad8d341a1a895fd7e21c10David Brown removeMessages(RETRY_TIMEOUT); 5003426afaf85d33d454fad8d341a1a895fd7e21c10David Brown sendEmptyMessageDelayed(RETRY_TIMEOUT, TIME_BETWEEN_RETRIES); 5013426afaf85d33d454fad8d341a1a895fd7e21c10David Brown } 5023426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 5033426afaf85d33d454fad8d341a1a895fd7e21c10David Brown private void cancelRetryTimer() { 5043426afaf85d33d454fad8d341a1a895fd7e21c10David Brown removeMessages(RETRY_TIMEOUT); 5053426afaf85d33d454fad8d341a1a895fd7e21c10David Brown } 5063426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 5073426afaf85d33d454fad8d341a1a895fd7e21c10David Brown private void registerForServiceStateChanged() { 5083426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // Unregister first, just to make sure we never register ourselves 5093426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // twice. (We need this because Phone.registerForServiceStateChanged() 5103426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // does not prevent multiple registration of the same handler.) 5113426afaf85d33d454fad8d341a1a895fd7e21c10David Brown mPhone.unregisterForServiceStateChanged(this); // Safe even if not currently registered 5123426afaf85d33d454fad8d341a1a895fd7e21c10David Brown mPhone.registerForServiceStateChanged(this, SERVICE_STATE_CHANGED, null); 5133426afaf85d33d454fad8d341a1a895fd7e21c10David Brown } 5143426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 5153426afaf85d33d454fad8d341a1a895fd7e21c10David Brown private void unregisterForServiceStateChanged() { 5163426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // This method is safe to call even if we haven't set mPhone yet. 5173426afaf85d33d454fad8d341a1a895fd7e21c10David Brown if (mPhone != null) { 5183426afaf85d33d454fad8d341a1a895fd7e21c10David Brown mPhone.unregisterForServiceStateChanged(this); // Safe even if unnecessary 5193426afaf85d33d454fad8d341a1a895fd7e21c10David Brown } 5203426afaf85d33d454fad8d341a1a895fd7e21c10David Brown removeMessages(SERVICE_STATE_CHANGED); // Clean up any pending messages too 5213426afaf85d33d454fad8d341a1a895fd7e21c10David Brown } 5223426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 5233426afaf85d33d454fad8d341a1a895fd7e21c10David Brown private void registerForDisconnect() { 5243426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // Note: no need to unregister first, since 5253426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // CallManager.registerForDisconnect() automatically prevents 5263426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // multiple registration of the same handler. 5273426afaf85d33d454fad8d341a1a895fd7e21c10David Brown mCM.registerForDisconnect(this, DISCONNECT, null); 5283426afaf85d33d454fad8d341a1a895fd7e21c10David Brown } 5293426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 5303426afaf85d33d454fad8d341a1a895fd7e21c10David Brown private void unregisterForDisconnect() { 5313426afaf85d33d454fad8d341a1a895fd7e21c10David Brown mCM.unregisterForDisconnect(this); // Safe even if not currently registered 5323426afaf85d33d454fad8d341a1a895fd7e21c10David Brown removeMessages(DISCONNECT); // Clean up any pending messages too 5333426afaf85d33d454fad8d341a1a895fd7e21c10David Brown } 5343426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 5353426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 5363426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // 5373426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // Debugging 5383426afaf85d33d454fad8d341a1a895fd7e21c10David Brown // 5393426afaf85d33d454fad8d341a1a895fd7e21c10David Brown 5403426afaf85d33d454fad8d341a1a895fd7e21c10David Brown private static void log(String msg) { 5413426afaf85d33d454fad8d341a1a895fd7e21c10David Brown Log.d(TAG, msg); 5423426afaf85d33d454fad8d341a1a895fd7e21c10David Brown } 5433426afaf85d33d454fad8d341a1a895fd7e21c10David Brown} 544