Home | History | Annotate | Download | only in phone
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.phone;
     18 
     19 import android.app.Activity;
     20 import android.app.Application;
     21 import android.app.ProgressDialog;
     22 import android.content.Intent;
     23 import android.os.AsyncResult;
     24 import android.os.Bundle;
     25 import android.os.Handler;
     26 import android.os.Message;
     27 import android.provider.Settings;
     28 import com.android.internal.telephony.Phone;
     29 import com.android.internal.telephony.PhoneFactory;
     30 import android.telephony.ServiceState;
     31 import android.view.WindowManager;
     32 
     33 /**
     34  * Helper class used by the InCallScreen to handle certain special
     35  * cases when making an emergency call.
     36  *
     37  * Specifically, if the user tries to dial an emergency number but the
     38  * radio is off, e.g. if the device is in airplane mode, this class is
     39  * responsible for turning the radio back on and retrying the call.
     40  *
     41  * This class is initially launched using the same intent originally
     42  * passed to the InCallScreen (presumably an ACTION_CALL_EMERGENCY intent)
     43  * but with this class explicitly set as the className/component.  Later,
     44  * we retry the emergency call by firing off that same intent, with the
     45  * component cleared, and using an integer extra called
     46  * EMERGENCY_CALL_RETRY_KEY to convey information about the current state.
     47  */
     48 public class EmergencyCallHandler extends Activity {
     49     /** the key used to get the count from our Intent's extra(s) */
     50     public static final String EMERGENCY_CALL_RETRY_KEY = "emergency_call_retry_count";
     51 
     52     /** count indicating an initial attempt at the call should be made. */
     53     public static final int INITIAL_ATTEMPT = -1;
     54 
     55     /** number of times to retry the call and the time spent in between attempts*/
     56     public static final int NUMBER_OF_RETRIES = 6;
     57     public static final int TIME_BETWEEN_RETRIES_MS = 5000;
     58 
     59     // constant events
     60     private static final int EVENT_SERVICE_STATE_CHANGED = 100;
     61     private static final int EVENT_TIMEOUT_EMERGENCY_CALL = 200;
     62 
     63     /**
     64      * Package holding information needed for the callback.
     65      */
     66     private static class EmergencyCallInfo {
     67         public Phone phone;
     68         public Intent intent;
     69         public ProgressDialog dialog;
     70         public Application app;
     71     }
     72 
     73     /**
     74      * static handler class, used to handle the two relevent events.
     75      */
     76     private static EmergencyCallEventHandler sHandler;
     77     private static class EmergencyCallEventHandler extends Handler {
     78         public void handleMessage(Message msg) {
     79             switch(msg.what) {
     80                 case EVENT_SERVICE_STATE_CHANGED: {
     81                         // make the initial call attempt after the radio is turned on.
     82                         ServiceState state = (ServiceState) ((AsyncResult) msg.obj).result;
     83                         if (state.getState() != ServiceState.STATE_POWER_OFF) {
     84                             EmergencyCallInfo eci =
     85                                 (EmergencyCallInfo) ((AsyncResult) msg.obj).userObj;
     86                             // deregister for the service state change events.
     87                             eci.phone.unregisterForServiceStateChanged(this);
     88                             eci.app.startActivity(eci.intent);
     89                             eci.dialog.dismiss();
     90                         }
     91                     }
     92                     break;
     93 
     94                 case EVENT_TIMEOUT_EMERGENCY_CALL: {
     95                         // repeated call after the timeout period.
     96                         EmergencyCallInfo eci = (EmergencyCallInfo) msg.obj;
     97                         eci.app.startActivity(eci.intent);
     98                         eci.dialog.dismiss();
     99                     }
    100                     break;
    101             }
    102         }
    103     }
    104 
    105     @Override
    106     protected void onCreate(Bundle icicle) {
    107         super.onCreate(icicle);
    108 
    109         // setup the phone and get the retry count embedded in the intent.
    110         Phone phone = PhoneFactory.getDefaultPhone();
    111         int retryCount = getIntent().getIntExtra(EMERGENCY_CALL_RETRY_KEY, INITIAL_ATTEMPT);
    112 
    113         // create a new message object.
    114         EmergencyCallInfo eci = new EmergencyCallInfo();
    115         eci.phone = phone;
    116         eci.app = getApplication();
    117         eci.dialog = constructDialog(retryCount);
    118 
    119         // The Intent we're going to fire off to retry the call is the
    120         // same one that got us here (except that we *don't* explicitly
    121         // specify this class as the component!)
    122         eci.intent = getIntent().setComponent(null);
    123         // And we'll be firing this Intent from the PhoneApp's context
    124         // (see the startActivity() calls above) so the
    125         // FLAG_ACTIVITY_NEW_TASK flag is required.
    126         eci.intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    127 
    128         // create the handler.
    129         if (sHandler == null) {
    130             sHandler = new EmergencyCallEventHandler();
    131         }
    132 
    133         // If this is the initial attempt, we need to register for a radio state
    134         // change and turn the radio on.  Otherwise, this is just a retry, and
    135         // we simply wait the alloted time before sending the request to try
    136         // the call again.
    137 
    138         // Note: The radio logic ITSELF will try its best to put the emergency
    139         // call through once the radio is turned on.  The retry we have here
    140         // is in case it fails; the current constants we have include making
    141         // 6 attempts, with a 5 second delay between each.
    142         if (retryCount == INITIAL_ATTEMPT) {
    143             // place the number of pending retries in the intent.
    144             eci.intent.putExtra(EMERGENCY_CALL_RETRY_KEY, NUMBER_OF_RETRIES);
    145 
    146             // turn the radio on and listen for it to complete.
    147             phone.registerForServiceStateChanged(sHandler,
    148                     EVENT_SERVICE_STATE_CHANGED, eci);
    149 
    150             // If airplane mode is on, we turn it off the same way that the
    151             // Settings activity turns it off.
    152             if (Settings.System.getInt(getContentResolver(),
    153                     Settings.System.AIRPLANE_MODE_ON, 0) > 0) {
    154                 // Change the system setting
    155                 Settings.System.putInt(getContentResolver(), Settings.System.AIRPLANE_MODE_ON, 0);
    156 
    157                 // Post the intent
    158                 Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
    159                 intent.putExtra("state", false);
    160                 sendBroadcast(intent);
    161 
    162             // Otherwise, for some strange reason the radio is just off, so
    163             // we just turn it back on.
    164             } else {
    165                 phone.setRadioPower(true);
    166             }
    167 
    168         } else {
    169             // decrement and store the number of retries.
    170             eci.intent.putExtra(EMERGENCY_CALL_RETRY_KEY, (retryCount - 1));
    171 
    172             // get the message and attach the data, then wait the alloted
    173             // time and send.
    174             Message m = sHandler.obtainMessage(EVENT_TIMEOUT_EMERGENCY_CALL);
    175             m.obj = eci;
    176             sHandler.sendMessageDelayed(m, TIME_BETWEEN_RETRIES_MS);
    177         }
    178         finish();
    179     }
    180 
    181     /**
    182      * create the dialog and hand it back to caller.
    183      */
    184     private ProgressDialog constructDialog(int retryCount) {
    185         // figure out the message to display.
    186         int msgId = (retryCount == INITIAL_ATTEMPT) ?
    187                 R.string.emergency_enable_radio_dialog_message :
    188                 R.string.emergency_enable_radio_dialog_retry;
    189 
    190         // create a system dialog that will persist outside this activity.
    191         ProgressDialog pd = new ProgressDialog(getApplication());
    192         pd.setTitle(getText(R.string.emergency_enable_radio_dialog_title));
    193         pd.setMessage(getText(msgId));
    194         pd.setIndeterminate(true);
    195         pd.setCancelable(false);
    196         pd.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
    197         pd.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
    198 
    199         // show the dialog
    200         pd.show();
    201 
    202         return pd;
    203     }
    204 }
    205