/* * Copyright (C) 2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.phone; import android.app.Activity; import android.app.Application; import android.app.ProgressDialog; import android.content.Intent; import android.os.AsyncResult; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.provider.Settings; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneFactory; import android.telephony.ServiceState; import android.view.WindowManager; /** * Helper class used by the InCallScreen to handle certain special * cases when making an emergency call. * * Specifically, if the user tries to dial an emergency number but the * radio is off, e.g. if the device is in airplane mode, this class is * responsible for turning the radio back on and retrying the call. * * This class is initially launched using the same intent originally * passed to the InCallScreen (presumably an ACTION_CALL_EMERGENCY intent) * but with this class explicitly set as the className/component. Later, * we retry the emergency call by firing off that same intent, with the * component cleared, and using an integer extra called * EMERGENCY_CALL_RETRY_KEY to convey information about the current state. */ public class EmergencyCallHandler extends Activity { /** the key used to get the count from our Intent's extra(s) */ public static final String EMERGENCY_CALL_RETRY_KEY = "emergency_call_retry_count"; /** count indicating an initial attempt at the call should be made. */ public static final int INITIAL_ATTEMPT = -1; /** number of times to retry the call and the time spent in between attempts*/ public static final int NUMBER_OF_RETRIES = 6; public static final int TIME_BETWEEN_RETRIES_MS = 5000; // constant events private static final int EVENT_SERVICE_STATE_CHANGED = 100; private static final int EVENT_TIMEOUT_EMERGENCY_CALL = 200; /** * Package holding information needed for the callback. */ private static class EmergencyCallInfo { public Phone phone; public Intent intent; public ProgressDialog dialog; public Application app; } /** * static handler class, used to handle the two relevent events. */ private static EmergencyCallEventHandler sHandler; private static class EmergencyCallEventHandler extends Handler { public void handleMessage(Message msg) { switch(msg.what) { case EVENT_SERVICE_STATE_CHANGED: { // make the initial call attempt after the radio is turned on. ServiceState state = (ServiceState) ((AsyncResult) msg.obj).result; if (state.getState() != ServiceState.STATE_POWER_OFF) { EmergencyCallInfo eci = (EmergencyCallInfo) ((AsyncResult) msg.obj).userObj; // deregister for the service state change events. eci.phone.unregisterForServiceStateChanged(this); eci.app.startActivity(eci.intent); eci.dialog.dismiss(); } } break; case EVENT_TIMEOUT_EMERGENCY_CALL: { // repeated call after the timeout period. EmergencyCallInfo eci = (EmergencyCallInfo) msg.obj; eci.app.startActivity(eci.intent); eci.dialog.dismiss(); } break; } } } @Override protected void onCreate(Bundle icicle) { super.onCreate(icicle); // setup the phone and get the retry count embedded in the intent. Phone phone = PhoneFactory.getDefaultPhone(); int retryCount = getIntent().getIntExtra(EMERGENCY_CALL_RETRY_KEY, INITIAL_ATTEMPT); // create a new message object. EmergencyCallInfo eci = new EmergencyCallInfo(); eci.phone = phone; eci.app = getApplication(); eci.dialog = constructDialog(retryCount); // The Intent we're going to fire off to retry the call is the // same one that got us here (except that we *don't* explicitly // specify this class as the component!) eci.intent = getIntent().setComponent(null); // And we'll be firing this Intent from the PhoneApp's context // (see the startActivity() calls above) so the // FLAG_ACTIVITY_NEW_TASK flag is required. eci.intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // create the handler. if (sHandler == null) { sHandler = new EmergencyCallEventHandler(); } // If this is the initial attempt, we need to register for a radio state // change and turn the radio on. Otherwise, this is just a retry, and // we simply wait the alloted time before sending the request to try // the call again. // Note: The radio logic ITSELF will try its best to put the emergency // call through once the radio is turned on. The retry we have here // is in case it fails; the current constants we have include making // 6 attempts, with a 5 second delay between each. if (retryCount == INITIAL_ATTEMPT) { // place the number of pending retries in the intent. eci.intent.putExtra(EMERGENCY_CALL_RETRY_KEY, NUMBER_OF_RETRIES); // turn the radio on and listen for it to complete. phone.registerForServiceStateChanged(sHandler, EVENT_SERVICE_STATE_CHANGED, eci); // If airplane mode is on, we turn it off the same way that the // Settings activity turns it off. if (Settings.System.getInt(getContentResolver(), Settings.System.AIRPLANE_MODE_ON, 0) > 0) { // Change the system setting Settings.System.putInt(getContentResolver(), Settings.System.AIRPLANE_MODE_ON, 0); // Post the intent Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); intent.putExtra("state", false); sendBroadcast(intent); // Otherwise, for some strange reason the radio is just off, so // we just turn it back on. } else { phone.setRadioPower(true); } } else { // decrement and store the number of retries. eci.intent.putExtra(EMERGENCY_CALL_RETRY_KEY, (retryCount - 1)); // get the message and attach the data, then wait the alloted // time and send. Message m = sHandler.obtainMessage(EVENT_TIMEOUT_EMERGENCY_CALL); m.obj = eci; sHandler.sendMessageDelayed(m, TIME_BETWEEN_RETRIES_MS); } finish(); } /** * create the dialog and hand it back to caller. */ private ProgressDialog constructDialog(int retryCount) { // figure out the message to display. int msgId = (retryCount == INITIAL_ATTEMPT) ? R.string.emergency_enable_radio_dialog_message : R.string.emergency_enable_radio_dialog_retry; // create a system dialog that will persist outside this activity. ProgressDialog pd = new ProgressDialog(getApplication()); pd.setTitle(getText(R.string.emergency_enable_radio_dialog_title)); pd.setMessage(getText(msgId)); pd.setIndeterminate(true); pd.setCancelable(false); pd.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG); pd.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND); // show the dialog pd.show(); return pd; } }