• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 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.Dialog;
21 import android.app.ProgressDialog;
22 import android.app.AlertDialog;
23 import android.content.BroadcastReceiver;
24 import android.content.ComponentName;
25 import android.content.Context;
26 import android.content.DialogInterface;
27 import android.content.DialogInterface.OnDismissListener;
28 import android.content.Intent;
29 import android.content.IntentFilter;
30 import android.content.ServiceConnection;
31 import android.content.res.Resources;
32 import android.os.AsyncResult;
33 import android.os.Bundle;
34 import android.os.CountDownTimer;
35 import android.os.Handler;
36 import android.os.IBinder;
37 import android.os.Looper;
38 import android.os.Message;
39 import android.os.SystemProperties;
40 import android.util.Log;
41 
42 import com.android.internal.telephony.Phone;
43 import com.android.internal.telephony.TelephonyIntents;
44 import com.android.internal.telephony.TelephonyProperties;
45 
46 /**
47  * Displays dialog that enables users to exit Emergency Callback Mode
48  *
49  * @see EmergencyCallbackModeService
50  */
51 public class EmergencyCallbackModeExitDialog extends Activity implements OnDismissListener {
52 
53     private static final String TAG = "EmergencyCallbackMode";
54 
55     /** Intent to trigger the Emergency Callback Mode exit dialog */
56     static final String ACTION_SHOW_ECM_EXIT_DIALOG =
57             "com.android.phone.action.ACTION_SHOW_ECM_EXIT_DIALOG";
58     /** Used to get the users choice from the return Intent's extra */
59     public static final String EXTRA_EXIT_ECM_RESULT = "exit_ecm_result";
60 
61     public static final int EXIT_ECM_BLOCK_OTHERS = 1;
62     public static final int EXIT_ECM_DIALOG = 2;
63     public static final int EXIT_ECM_PROGRESS_DIALOG = 3;
64     public static final int EXIT_ECM_IN_EMERGENCY_CALL_DIALOG = 4;
65 
66     AlertDialog mAlertDialog = null;
67     ProgressDialog mProgressDialog = null;
68     CountDownTimer mTimer = null;
69     EmergencyCallbackModeService mService = null;
70     Handler mHandler = null;
71     int mDialogType = 0;
72     long mEcmTimeout = 0;
73     private boolean mInEmergencyCall = false;
74     private static final int ECM_TIMER_RESET = 1;
75     private Phone mPhone = null;
76 
77     @Override
onCreate(Bundle savedInstanceState)78     public void onCreate(Bundle savedInstanceState) {
79         super.onCreate(savedInstanceState);
80 
81         mPhone = PhoneGlobals.getInstance().getPhoneInEcm();
82         // Check if phone is in Emergency Callback Mode. If not, exit.
83         if (mPhone == null || !mPhone.isInEcm()) {
84             if (mPhone == null) {
85               android.util.EventLog.writeEvent(0x534e4554, "79995313", -1, "");
86             }
87             Log.i(TAG, "ECMModeExitDialog launched - isInEcm: false" + " phone:" + mPhone);
88             finish();
89             return;
90         }
91 
92         mHandler = new Handler();
93 
94         // Start thread that will wait for the connection completion so that it can get
95         // timeout value from the service
96         Thread waitForConnectionCompleteThread = new Thread(null, mTask,
97                 "EcmExitDialogWaitThread");
98         waitForConnectionCompleteThread.start();
99 
100         // Register ECM timer reset notfication
101         mPhone.registerForEcmTimerReset(mTimerResetHandler, ECM_TIMER_RESET, null);
102 
103         // Register receiver for intent closing the dialog
104         IntentFilter filter = new IntentFilter();
105         filter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
106         registerReceiver(mEcmExitReceiver, filter);
107     }
108 
109     @Override
onDestroy()110     public void onDestroy() {
111         super.onDestroy();
112         try {
113             unregisterReceiver(mEcmExitReceiver);
114         } catch (IllegalArgumentException e) {
115             // Receiver was never registered - silently ignore.
116         }
117         // Unregister ECM timer reset notification
118         if (mPhone != null) {
119             mPhone.unregisterForEcmTimerReset(mHandler);
120         }
121     }
122 
123     @Override
onRestoreInstanceState(Bundle savedInstanceState)124     protected void onRestoreInstanceState(Bundle savedInstanceState) {
125         super.onRestoreInstanceState(savedInstanceState);
126         mDialogType = savedInstanceState.getInt("DIALOG_TYPE");
127     }
128 
129     @Override
onSaveInstanceState(Bundle outState)130     protected void onSaveInstanceState(Bundle outState) {
131         super.onSaveInstanceState(outState);
132         outState.putInt("DIALOG_TYPE", mDialogType);
133     }
134 
135     /**
136      * Waits until bind to the service completes
137      */
138     private Runnable mTask = new Runnable() {
139         public void run() {
140             Looper.prepare();
141 
142             // Bind to the remote service
143             bindService(new Intent(EmergencyCallbackModeExitDialog.this,
144                     EmergencyCallbackModeService.class), mConnection, Context.BIND_AUTO_CREATE);
145 
146             // Wait for bind to finish
147             synchronized (EmergencyCallbackModeExitDialog.this) {
148                 try {
149                     if (mService == null) {
150                         EmergencyCallbackModeExitDialog.this.wait();
151                     }
152                 } catch (InterruptedException e) {
153                     Log.d("ECM", "EmergencyCallbackModeExitDialog InterruptedException: "
154                             + e.getMessage());
155                     e.printStackTrace();
156                 }
157             }
158 
159             // Get timeout value and call state from the service
160             if (mService != null) {
161                 mEcmTimeout = mService.getEmergencyCallbackModeTimeout();
162                 mInEmergencyCall = mService.getEmergencyCallbackModeCallState();
163                 try {
164                     // Unbind from remote service
165                     unbindService(mConnection);
166                 } catch (IllegalArgumentException e) {
167                     // Failed to unbind from service. Don't crash as this brings down the entire
168                     // radio.
169                     Log.w(TAG, "Failed to unbind from EmergencyCallbackModeService");
170                 }
171             }
172 
173             // Show dialog
174             mHandler.post(new Runnable() {
175                 public void run() {
176                     showEmergencyCallbackModeExitDialog();
177                 }
178             });
179         }
180     };
181 
182     /**
183      * Shows Emergency Callback Mode dialog and starts countdown timer
184      */
showEmergencyCallbackModeExitDialog()185     private void showEmergencyCallbackModeExitDialog() {
186         if (!this.isResumed()) {
187             Log.w(TAG, "Tried to show dialog, but activity was already finished");
188             return;
189         }
190         if(mInEmergencyCall) {
191             mDialogType = EXIT_ECM_IN_EMERGENCY_CALL_DIALOG;
192             showDialog(EXIT_ECM_IN_EMERGENCY_CALL_DIALOG);
193         } else {
194             if (getIntent().getAction().equals(
195                     TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS)) {
196                 mDialogType = EXIT_ECM_BLOCK_OTHERS;
197                 showDialog(EXIT_ECM_BLOCK_OTHERS);
198             } else if (getIntent().getAction().equals(ACTION_SHOW_ECM_EXIT_DIALOG)) {
199                 mDialogType = EXIT_ECM_DIALOG;
200                 showDialog(EXIT_ECM_DIALOG);
201             }
202 
203             mTimer = new CountDownTimer(mEcmTimeout, 1000) {
204                 @Override
205                 public void onTick(long millisUntilFinished) {
206                     CharSequence text = getDialogText(millisUntilFinished);
207                     mAlertDialog.setMessage(text);
208                 }
209 
210                 @Override
211                 public void onFinish() {
212                     //Do nothing
213                 }
214             }.start();
215         }
216     }
217 
218     /**
219      * Creates dialog that enables users to exit Emergency Callback Mode
220      */
221     @Override
onCreateDialog(int id)222     protected Dialog onCreateDialog(int id) {
223         switch (id) {
224         case EXIT_ECM_BLOCK_OTHERS:
225         case EXIT_ECM_DIALOG:
226             CharSequence text = getDialogText(mEcmTimeout);
227             mAlertDialog = new AlertDialog.Builder(EmergencyCallbackModeExitDialog.this)
228                     .setIcon(R.drawable.ic_emergency_callback_mode)
229                     .setTitle(R.string.phone_in_ecm_notification_title)
230                     .setMessage(text)
231                     .setPositiveButton(R.string.alert_dialog_yes,
232                             new DialogInterface.OnClickListener() {
233                                 public void onClick(DialogInterface dialog,int whichButton) {
234                                     // User clicked Yes. Exit Emergency Callback Mode.
235                                     mPhone.exitEmergencyCallbackMode();
236 
237                                     // Show progress dialog
238                                     showDialog(EXIT_ECM_PROGRESS_DIALOG);
239                                     mTimer.cancel();
240                                 }
241                             })
242                     .setNegativeButton(R.string.alert_dialog_no,
243                             new DialogInterface.OnClickListener() {
244                                 public void onClick(DialogInterface dialog, int whichButton) {
245                                     // User clicked No
246                                     setResult(RESULT_OK, (new Intent()).putExtra(
247                                             EXTRA_EXIT_ECM_RESULT, false));
248                                     finish();
249                                 }
250                             }).create();
251             mAlertDialog.setOnDismissListener(this);
252             return mAlertDialog;
253 
254         case EXIT_ECM_IN_EMERGENCY_CALL_DIALOG:
255             mAlertDialog = new AlertDialog.Builder(EmergencyCallbackModeExitDialog.this)
256                     .setIcon(R.drawable.ic_emergency_callback_mode)
257                     .setTitle(R.string.phone_in_ecm_notification_title)
258                     .setMessage(R.string.alert_dialog_in_ecm_call)
259                     .setNeutralButton(R.string.alert_dialog_dismiss,
260                             new DialogInterface.OnClickListener() {
261                                 public void onClick(DialogInterface dialog, int whichButton) {
262                                     // User clicked Dismiss
263                                     setResult(RESULT_OK, (new Intent()).putExtra(
264                                             EXTRA_EXIT_ECM_RESULT, false));
265                                     finish();
266                                 }
267                             }).create();
268             mAlertDialog.setOnDismissListener(this);
269             return mAlertDialog;
270 
271         case EXIT_ECM_PROGRESS_DIALOG:
272             mProgressDialog = new ProgressDialog(EmergencyCallbackModeExitDialog.this);
273             mProgressDialog.setMessage(getText(R.string.progress_dialog_exiting_ecm));
274             mProgressDialog.setIndeterminate(true);
275             mProgressDialog.setCancelable(false);
276             return mProgressDialog;
277 
278         default:
279             return null;
280         }
281     }
282 
283     /**
284      * Returns dialog box text with updated timeout value
285      */
getDialogText(long millisUntilFinished)286     private CharSequence getDialogText(long millisUntilFinished) {
287         // Format time
288         int minutes = (int)(millisUntilFinished / 60000);
289         String time = String.format("%d:%02d", minutes,
290                 (millisUntilFinished % 60000) / 1000);
291 
292         switch (mDialogType) {
293         case EXIT_ECM_BLOCK_OTHERS:
294             return String.format(getResources().getQuantityText(
295                     R.plurals.alert_dialog_not_avaialble_in_ecm, minutes).toString(), time);
296         case EXIT_ECM_DIALOG:
297             return String.format(getResources().getQuantityText(R.plurals.alert_dialog_exit_ecm,
298                     minutes).toString(), time);
299         }
300         return null;
301     }
302 
303     /**
304      * Closes activity when dialog is dismissed
305      */
306     @Override
onDismiss(DialogInterface dialog)307     public void onDismiss(DialogInterface dialog) {
308         EmergencyCallbackModeExitDialog.this.setResult(RESULT_OK, (new Intent())
309                 .putExtra(EXTRA_EXIT_ECM_RESULT, false));
310         finish();
311     }
312 
313     /**
314      * Listens for Emergency Callback Mode state change intents
315      */
316     private BroadcastReceiver mEcmExitReceiver = new BroadcastReceiver() {
317         @Override
318         public void onReceive(Context context, Intent intent) {
319             // Received exit Emergency Callback Mode notification close all dialogs
320             if (intent.getAction().equals(
321                     TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) {
322                 if (intent.getBooleanExtra("phoneinECMState", false) == false) {
323                     if (mAlertDialog != null)
324                         mAlertDialog.dismiss();
325                     if (mProgressDialog != null)
326                         mProgressDialog.dismiss();
327                     EmergencyCallbackModeExitDialog.this.setResult(RESULT_OK, (new Intent())
328                             .putExtra(EXTRA_EXIT_ECM_RESULT, true));
329                     finish();
330                 }
331             }
332         }
333     };
334 
335     /**
336      * Class for interacting with the interface of the service
337      */
338     private ServiceConnection mConnection = new ServiceConnection() {
339         public void onServiceConnected(ComponentName className, IBinder service) {
340             mService = ((EmergencyCallbackModeService.LocalBinder)service).getService();
341             // Notify thread that connection is ready
342             synchronized (EmergencyCallbackModeExitDialog.this) {
343                 EmergencyCallbackModeExitDialog.this.notify();
344             }
345         }
346 
347         public void onServiceDisconnected(ComponentName className) {
348             mService = null;
349         }
350     };
351 
352     /**
353      * Class for receiving framework timer reset notifications
354      */
355     private Handler mTimerResetHandler = new Handler () {
356         public void handleMessage(Message msg) {
357             switch (msg.what) {
358                 case ECM_TIMER_RESET:
359                     if(!((Boolean)((AsyncResult) msg.obj).result).booleanValue()) {
360                         EmergencyCallbackModeExitDialog.this.setResult(RESULT_OK, (new Intent())
361                                 .putExtra(EXTRA_EXIT_ECM_RESULT, false));
362                         finish();
363                     }
364                     break;
365             }
366         }
367     };
368 }
369