• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 {
handleMessage(Message msg)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
onCreate(Bundle icicle)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      */
constructDialog(int retryCount)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