blob: fd6510b0e8eb1ed28183e3f209fe8ca4e5358962 [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";
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
75 public void onCreate(Bundle savedInstanceState) {
76 super.onCreate(savedInstanceState);
77
Sandeep Kuntade73a6a2014-10-15 18:45:56 +053078 mPhone = PhoneGlobals.getInstance().getPhoneInEcm();
Santos Cordon7d4ddf62013-07-10 11:58:08 -070079 // Check if phone is in Emergency Callback Mode. If not, exit.
Brad Ebinger6d4ef742018-02-07 10:59:33 -080080 if (mPhone == null || !mPhone.isInEcm()) {
81 Log.i(TAG, "ECMModeExitDialog launched - isInEcm: false" + " phone:" + mPhone);
Santos Cordon7d4ddf62013-07-10 11:58:08 -070082 finish();
Yorke Lee34a72cb2014-10-12 13:17:04 -070083 return;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070084 }
Brad Ebinger6d4ef742018-02-07 10:59:33 -080085 Log.i(TAG, "ECMModeExitDialog launched - isInEcm: true" + " phone:" + mPhone);
Santos Cordon7d4ddf62013-07-10 11:58:08 -070086
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
Santos Cordon7d4ddf62013-07-10 11:58:08 -070096 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
105 public void onDestroy() {
106 super.onDestroy();
Yorke Lee34a72cb2014-10-12 13:17:04 -0700107 try {
108 unregisterReceiver(mEcmExitReceiver);
109 } catch (IllegalArgumentException e) {
110 // Receiver was never registered - silently ignore.
111 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700112 // Unregister ECM timer reset notification
Yorke Lee34a72cb2014-10-12 13:17:04 -0700113 if (mPhone != null) {
114 mPhone.unregisterForEcmTimerReset(mHandler);
115 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700116 }
117
118 @Override
119 protected void onRestoreInstanceState(Bundle savedInstanceState) {
120 super.onRestoreInstanceState(savedInstanceState);
121 mDialogType = savedInstanceState.getInt("DIALOG_TYPE");
122 }
123
124 @Override
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();
Yorke Lee34a72cb2014-10-12 13:17:04 -0700158 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 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700166 }
167
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700168 // 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 */
180 private void showEmergencyCallbackModeExitDialog() {
Yorke Lee34a72cb2014-10-12 13:17:04 -0700181 if (!this.isResumed()) {
182 Log.w(TAG, "Tried to show dialog, but activity was already finished");
183 return;
184 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700185 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
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);
Brad Ebinger1a3fa362018-04-19 13:43:31 -0700222 mAlertDialog = new AlertDialog.Builder(EmergencyCallbackModeExitDialog.this,
223 android.R.style.Theme_DeviceDefault_Dialog_Alert)
Tyler Gunn625eb0b2014-08-27 20:37:32 -0700224 .setIcon(R.drawable.ic_emergency_callback_mode)
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700225 .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();
Li Wei65667ea2017-08-02 16:06:59 +0800247 mAlertDialog.setOnCancelListener(this);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700248 return mAlertDialog;
249
250 case EXIT_ECM_IN_EMERGENCY_CALL_DIALOG:
Brad Ebinger1a3fa362018-04-19 13:43:31 -0700251 mAlertDialog = new AlertDialog.Builder(EmergencyCallbackModeExitDialog.this,
252 android.R.style.Theme_DeviceDefault_Dialog_Alert)
Tyler Gunn625eb0b2014-08-27 20:37:32 -0700253 .setIcon(R.drawable.ic_emergency_callback_mode)
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700254 .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();
Li Wei65667ea2017-08-02 16:06:59 +0800265 mAlertDialog.setOnCancelListener(this);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700266 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 */
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 /**
Li Wei65667ea2017-08-02 16:06:59 +0800301 * Closes activity when dialog is canceled
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700302 */
Yorke Lee34a72cb2014-10-12 13:17:04 -0700303 @Override
Li Wei65667ea2017-08-02 16:06:59 +0800304 public void onCancel(DialogInterface dialog) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700305 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}