blob: 2492f4694d76d4a25b0856764f23b66fb6025e1f [file] [log] [blame]
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001/*
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
17package com.android.phone;
18
19import android.app.Activity;
Brad Ebinger6d4ef742018-02-07 10:59:33 -080020import android.app.AlertDialog;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070021import android.app.Dialog;
22import android.app.ProgressDialog;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070023import android.content.BroadcastReceiver;
24import android.content.ComponentName;
25import android.content.Context;
26import android.content.DialogInterface;
Li Wei65667ea2017-08-02 16:06:59 +080027import android.content.DialogInterface.OnCancelListener;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070028import android.content.Intent;
29import android.content.IntentFilter;
30import android.content.ServiceConnection;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070031import android.os.AsyncResult;
32import android.os.Bundle;
33import android.os.CountDownTimer;
34import android.os.Handler;
35import android.os.IBinder;
36import android.os.Looper;
37import android.os.Message;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070038import android.util.Log;
39
40import com.android.internal.telephony.Phone;
41import com.android.internal.telephony.TelephonyIntents;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070042
43/**
44 * Displays dialog that enables users to exit Emergency Callback Mode
45 *
46 * @see EmergencyCallbackModeService
47 */
Li Wei65667ea2017-08-02 16:06:59 +080048public class EmergencyCallbackModeExitDialog extends Activity implements OnCancelListener {
Santos Cordon7d4ddf62013-07-10 11:58:08 -070049
Yorke Lee34a72cb2014-10-12 13:17:04 -070050 private static final String TAG = "EmergencyCallbackMode";
51
Santos Cordon7d4ddf62013-07-10 11:58:08 -070052 /** 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";
Santos Cordon7d4ddf62013-07-10 11:58:08 -070055
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
73 public void onCreate(Bundle savedInstanceState) {
74 super.onCreate(savedInstanceState);
75
Sandeep Kuntade73a6a2014-10-15 18:45:56 +053076 mPhone = PhoneGlobals.getInstance().getPhoneInEcm();
Santos Cordon7d4ddf62013-07-10 11:58:08 -070077 // Check if phone is in Emergency Callback Mode. If not, exit.
Brad Ebinger6d4ef742018-02-07 10:59:33 -080078 if (mPhone == null || !mPhone.isInEcm()) {
79 Log.i(TAG, "ECMModeExitDialog launched - isInEcm: false" + " phone:" + mPhone);
Santos Cordon7d4ddf62013-07-10 11:58:08 -070080 finish();
Yorke Lee34a72cb2014-10-12 13:17:04 -070081 return;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070082 }
Brad Ebinger6d4ef742018-02-07 10:59:33 -080083 Log.i(TAG, "ECMModeExitDialog launched - isInEcm: true" + " phone:" + mPhone);
Santos Cordon7d4ddf62013-07-10 11:58:08 -070084
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
Santos Cordon7d4ddf62013-07-10 11:58:08 -070094 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
103 public void onDestroy() {
104 super.onDestroy();
Yorke Lee34a72cb2014-10-12 13:17:04 -0700105 try {
106 unregisterReceiver(mEcmExitReceiver);
107 } catch (IllegalArgumentException e) {
108 // Receiver was never registered - silently ignore.
109 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700110 // Unregister ECM timer reset notification
Yorke Lee34a72cb2014-10-12 13:17:04 -0700111 if (mPhone != null) {
112 mPhone.unregisterForEcmTimerReset(mHandler);
113 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700114 }
115
116 @Override
117 protected void onRestoreInstanceState(Bundle savedInstanceState) {
118 super.onRestoreInstanceState(savedInstanceState);
119 mDialogType = savedInstanceState.getInt("DIALOG_TYPE");
120 }
121
122 @Override
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();
Yorke Lee34a72cb2014-10-12 13:17:04 -0700156 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 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700164 }
165
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700166 // 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 */
178 private void showEmergencyCallbackModeExitDialog() {
Yorke Lee34a72cb2014-10-12 13:17:04 -0700179 if (!this.isResumed()) {
180 Log.w(TAG, "Tried to show dialog, but activity was already finished");
181 return;
182 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700183 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
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);
Brad Ebinger1a3fa362018-04-19 13:43:31 -0700220 mAlertDialog = new AlertDialog.Builder(EmergencyCallbackModeExitDialog.this,
221 android.R.style.Theme_DeviceDefault_Dialog_Alert)
Tyler Gunn625eb0b2014-08-27 20:37:32 -0700222 .setIcon(R.drawable.ic_emergency_callback_mode)
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700223 .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
Pengquan Meng252acb32018-10-11 17:16:25 -0700240 setResult(RESULT_CANCELED);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700241 finish();
242 }
243 }).create();
Li Wei65667ea2017-08-02 16:06:59 +0800244 mAlertDialog.setOnCancelListener(this);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700245 return mAlertDialog;
246
247 case EXIT_ECM_IN_EMERGENCY_CALL_DIALOG:
Brad Ebinger1a3fa362018-04-19 13:43:31 -0700248 mAlertDialog = new AlertDialog.Builder(EmergencyCallbackModeExitDialog.this,
249 android.R.style.Theme_DeviceDefault_Dialog_Alert)
Tyler Gunn625eb0b2014-08-27 20:37:32 -0700250 .setIcon(R.drawable.ic_emergency_callback_mode)
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700251 .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
Pengquan Meng252acb32018-10-11 17:16:25 -0700257 setResult(RESULT_CANCELED);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700258 finish();
259 }
260 }).create();
Li Wei65667ea2017-08-02 16:06:59 +0800261 mAlertDialog.setOnCancelListener(this);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700262 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 */
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 /**
Li Wei65667ea2017-08-02 16:06:59 +0800297 * Closes activity when dialog is canceled
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700298 */
Yorke Lee34a72cb2014-10-12 13:17:04 -0700299 @Override
Li Wei65667ea2017-08-02 16:06:59 +0800300 public void onCancel(DialogInterface dialog) {
Pengquan Meng252acb32018-10-11 17:16:25 -0700301 EmergencyCallbackModeExitDialog.this.setResult(RESULT_CANCELED);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700302 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();
Pengquan Meng252acb32018-10-11 17:16:25 -0700319 EmergencyCallbackModeExitDialog.this.setResult(RESULT_OK);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700320 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()) {
Pengquan Meng252acb32018-10-11 17:16:25 -0700351 EmergencyCallbackModeExitDialog.this.setResult(RESULT_CANCELED);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700352 finish();
353 }
354 break;
355 }
356 }
357 };
358}