OSDN Git Service

original
[gb-231r1-is01/Gingerbread_2.3.3_r1_IS01.git] / packages / apps / Phone / src / com / android / phone / EmergencyCallHandler.java
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 android.telephony.ServiceState;
29 import android.util.Log;
30 import android.view.WindowManager;
31
32 import com.android.internal.telephony.Phone;
33 import com.android.internal.telephony.PhoneFactory;
34
35 /**
36  * Helper class used by the InCallScreen to handle certain special
37  * cases when making an emergency call.
38  *
39  * Specifically, if the user tries to dial an emergency number but the
40  * radio is off, e.g. if the device is in airplane mode, this class is
41  * responsible for turning the radio back on and retrying the call.
42  *
43  * This class is initially launched using the same intent originally
44  * passed to the InCallScreen (presumably an ACTION_CALL_EMERGENCY intent)
45  * but with this class explicitly set as the className/component.  Later,
46  * we retry the emergency call by firing off that same intent, with the
47  * component cleared, and using an integer extra called
48  * EMERGENCY_CALL_RETRY_KEY to convey information about the current state.
49  */
50 public class EmergencyCallHandler extends Activity {
51     private static final String TAG = "EmergencyCallHandler";
52     private static final boolean DBG = true;  // OK to have this on by default
53
54     /** the key used to get the count from our Intent's extra(s) */
55     public static final String EMERGENCY_CALL_RETRY_KEY = "emergency_call_retry_count";
56     
57     /** count indicating an initial attempt at the call should be made. */
58     public static final int INITIAL_ATTEMPT = -1;
59     
60     /** number of times to retry the call and the time spent in between attempts*/
61     public static final int NUMBER_OF_RETRIES = 6;
62     public static final int TIME_BETWEEN_RETRIES_MS = 5000;
63     
64     // constant events
65     private static final int EVENT_SERVICE_STATE_CHANGED = 100;
66     private static final int EVENT_TIMEOUT_EMERGENCY_CALL = 200;
67     
68     /**
69      * Package holding information needed for the callback.
70      */
71     private static class EmergencyCallInfo {
72         public Phone phone;
73         public Intent intent;
74         public ProgressDialog dialog;
75         public Application app;
76     }
77     
78     /**
79      * static handler class, used to handle the two relevent events. 
80      */
81     private static EmergencyCallEventHandler sHandler;
82     private static class EmergencyCallEventHandler extends Handler {
83         public void handleMessage(Message msg) {
84             switch(msg.what) {
85                 case EVENT_SERVICE_STATE_CHANGED: {
86                         // make the initial call attempt after the radio is turned on.
87                         ServiceState state = (ServiceState) ((AsyncResult) msg.obj).result;
88                         if (DBG) Log.d(TAG, "EVENT_SERVICE_STATE_CHANGED: state = " + state);
89                         if (state.getState() != ServiceState.STATE_POWER_OFF) {
90                             EmergencyCallInfo eci = 
91                                 (EmergencyCallInfo) ((AsyncResult) msg.obj).userObj;
92                             // deregister for the service state change events. 
93                             eci.phone.unregisterForServiceStateChanged(this);
94                             eci.dialog.dismiss();
95
96                             if (DBG) Log.d(TAG, "About to (re)launch InCallScreen: " + eci.intent);
97                             eci.app.startActivity(eci.intent);
98                         }
99                     }
100                     break;
101
102                 case EVENT_TIMEOUT_EMERGENCY_CALL: {
103                         if (DBG) Log.d(TAG, "EVENT_TIMEOUT_EMERGENCY_CALL...");
104                         // repeated call after the timeout period.
105                         EmergencyCallInfo eci = (EmergencyCallInfo) msg.obj;
106                         eci.dialog.dismiss();
107
108                         if (DBG) Log.d(TAG, "About to (re)launch InCallScreen: " + eci.intent);
109                         eci.app.startActivity(eci.intent);
110                     }
111                     break;
112             }
113         }
114     }
115
116     @Override
117     protected void onCreate(Bundle icicle) {
118         Log.i(TAG, "onCreate()...  intent = " + getIntent());
119         super.onCreate(icicle);
120
121         // Watch out: the intent action we get here should always be
122         // ACTION_CALL_EMERGENCY, since the whole point of this activity
123         // is for it to be launched using the same intent originally
124         // passed to the InCallScreen, which will always be
125         // ACTION_CALL_EMERGENCY when making an emergency call.
126         //
127         // If we ever get launched with any other action, especially if it's
128         // "com.android.phone.InCallScreen.UNDEFINED" (as in bug 3094858), that
129         // almost certainly indicates a logic bug in the InCallScreen.
130         if (!Intent.ACTION_CALL_EMERGENCY.equals(getIntent().getAction())) {
131             Log.w(TAG, "Unexpected intent action!  Should be ACTION_CALL_EMERGENCY, "
132                   + "but instead got: " + getIntent().getAction());
133         }
134
135         // setup the phone and get the retry count embedded in the intent.
136         Phone phone = PhoneFactory.getDefaultPhone();
137         int retryCount = getIntent().getIntExtra(EMERGENCY_CALL_RETRY_KEY, INITIAL_ATTEMPT);
138         
139         // create a new message object.
140         EmergencyCallInfo eci = new EmergencyCallInfo();
141         eci.phone = phone;
142         eci.app = getApplication();
143         eci.dialog = constructDialog(retryCount);
144
145         // The Intent we're going to fire off to retry the call is the
146         // same one that got us here (except that we *don't* explicitly
147         // specify this class as the component!)
148         eci.intent = getIntent().setComponent(null);
149         // And we'll be firing this Intent from the PhoneApp's context
150         // (see the startActivity() calls above) so the
151         // FLAG_ACTIVITY_NEW_TASK flag is required.
152         eci.intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
153         if (DBG) Log.d(TAG, "- initial eci.intent: " + eci.intent);
154
155         // create the handler.
156         if (sHandler == null) {
157             sHandler = new EmergencyCallEventHandler();
158         }
159         
160         // If this is the initial attempt, we need to register for a radio state
161         // change and turn the radio on.  Otherwise, this is just a retry, and
162         // we simply wait the alloted time before sending the request to try
163         // the call again.
164         
165         // Note: The radio logic ITSELF will try its best to put the emergency
166         // call through once the radio is turned on.  The retry we have here 
167         // is in case it fails; the current constants we have include making
168         // 6 attempts, with a 5 second delay between each.
169         if (retryCount == INITIAL_ATTEMPT) {
170             // place the number of pending retries in the intent.
171             eci.intent.putExtra(EMERGENCY_CALL_RETRY_KEY, NUMBER_OF_RETRIES);
172             
173             // turn the radio on and listen for it to complete.
174             phone.registerForServiceStateChanged(sHandler, 
175                     EVENT_SERVICE_STATE_CHANGED, eci);
176
177             // If airplane mode is on, we turn it off the same way that the 
178             // Settings activity turns it off.
179             if (Settings.System.getInt(getContentResolver(), 
180                     Settings.System.AIRPLANE_MODE_ON, 0) > 0) {
181                 if (DBG) Log.d(TAG, "Turning off airplane mode...");
182
183                 // Change the system setting
184                 Settings.System.putInt(getContentResolver(), Settings.System.AIRPLANE_MODE_ON, 0);
185                 
186                 // Post the intent
187                 Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
188                 intent.putExtra("state", false);
189                 sendBroadcast(intent);
190
191             // Otherwise, for some strange reason the radio is just off, so 
192             // we just turn it back on.
193             } else {
194                 if (DBG) Log.d(TAG, "Manually powering radio on...");
195                 phone.setRadioPower(true);
196             }
197             
198         } else {
199             // decrement and store the number of retries.
200             if (DBG) Log.d(TAG, "Retry attempt...  retryCount = " + retryCount);
201             eci.intent.putExtra(EMERGENCY_CALL_RETRY_KEY, (retryCount - 1));
202             
203             // get the message and attach the data, then wait the alloted
204             // time and send.
205             Message m = sHandler.obtainMessage(EVENT_TIMEOUT_EMERGENCY_CALL);
206             m.obj = eci;
207             sHandler.sendMessageDelayed(m, TIME_BETWEEN_RETRIES_MS);
208         }
209         finish();
210     }
211     
212     /**
213      * create the dialog and hand it back to caller.
214      */
215     private ProgressDialog constructDialog(int retryCount) {
216         // figure out the message to display. 
217         int msgId = (retryCount == INITIAL_ATTEMPT) ? 
218                 R.string.emergency_enable_radio_dialog_message :
219                 R.string.emergency_enable_radio_dialog_retry;
220
221         // create a system dialog that will persist outside this activity.
222         ProgressDialog pd = new ProgressDialog(getApplication());
223         pd.setTitle(getText(R.string.emergency_enable_radio_dialog_title));
224         pd.setMessage(getText(msgId));
225         pd.setIndeterminate(true);
226         pd.setCancelable(false);
227         pd.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
228         pd.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
229         
230         // show the dialog
231         pd.show();
232         
233         return pd;
234     }
235
236     @Override
237     protected void onNewIntent(Intent intent) {
238         // We shouldn't ever get here, since we should never be launched in
239         // "singleTop" mode in the first place.
240         Log.w(TAG, "Unexpected call to onNewIntent(): intent=" + intent);
241         super.onNewIntent(intent);
242     }
243 }