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