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