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