blob: adba850260fe2e38da424844c2ec11aef9c5ebfe [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
Shuo Qian479dd9e2021-02-22 18:32:21 -080019import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
20
Santos Cordon7d4ddf62013-07-10 11:58:08 -070021import android.app.Activity;
Brad Ebinger6d4ef742018-02-07 10:59:33 -080022import android.app.AlertDialog;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070023import android.app.Dialog;
24import android.app.ProgressDialog;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070025import android.content.BroadcastReceiver;
26import android.content.ComponentName;
27import android.content.Context;
28import android.content.DialogInterface;
Li Wei65667ea2017-08-02 16:06:59 +080029import android.content.DialogInterface.OnCancelListener;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070030import android.content.Intent;
31import android.content.IntentFilter;
32import android.content.ServiceConnection;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070033import android.os.AsyncResult;
34import android.os.Bundle;
35import android.os.CountDownTimer;
36import android.os.Handler;
37import android.os.IBinder;
38import android.os.Looper;
39import android.os.Message;
Brad Ebinger3b3c30a2020-03-18 13:59:44 -070040import android.telephony.TelephonyManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070041import android.util.Log;
42
43import com.android.internal.telephony.Phone;
44import com.android.internal.telephony.TelephonyIntents;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070045
46/**
47 * Displays dialog that enables users to exit Emergency Callback Mode
48 *
49 * @see EmergencyCallbackModeService
50 */
Li Wei65667ea2017-08-02 16:06:59 +080051public class EmergencyCallbackModeExitDialog extends Activity implements OnCancelListener {
Santos Cordon7d4ddf62013-07-10 11:58:08 -070052
Yorke Lee34a72cb2014-10-12 13:17:04 -070053 private static final String TAG = "EmergencyCallbackMode";
54
Santos Cordon7d4ddf62013-07-10 11:58:08 -070055 /** Intent to trigger the Emergency Callback Mode exit dialog */
56 static final String ACTION_SHOW_ECM_EXIT_DIALOG =
57 "com.android.phone.action.ACTION_SHOW_ECM_EXIT_DIALOG";
Santos Cordon7d4ddf62013-07-10 11:58:08 -070058
59 public static final int EXIT_ECM_BLOCK_OTHERS = 1;
60 public static final int EXIT_ECM_DIALOG = 2;
61 public static final int EXIT_ECM_PROGRESS_DIALOG = 3;
62 public static final int EXIT_ECM_IN_EMERGENCY_CALL_DIALOG = 4;
63
64 AlertDialog mAlertDialog = null;
65 ProgressDialog mProgressDialog = null;
66 CountDownTimer mTimer = null;
67 EmergencyCallbackModeService mService = null;
68 Handler mHandler = null;
69 int mDialogType = 0;
70 long mEcmTimeout = 0;
71 private boolean mInEmergencyCall = false;
72 private static final int ECM_TIMER_RESET = 1;
73 private Phone mPhone = null;
Jordan Liu1cfab0d2019-09-27 11:17:52 -070074 private boolean mIsResumed = false;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070075
76 @Override
77 public void onCreate(Bundle savedInstanceState) {
78 super.onCreate(savedInstanceState);
Shuo Qian479dd9e2021-02-22 18:32:21 -080079 getWindow().addPrivateFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
Sandeep Kuntade73a6a2014-10-15 18:45:56 +053080 mPhone = PhoneGlobals.getInstance().getPhoneInEcm();
Santos Cordon7d4ddf62013-07-10 11:58:08 -070081 // Check if phone is in Emergency Callback Mode. If not, exit.
Brad Ebinger6d4ef742018-02-07 10:59:33 -080082 if (mPhone == null || !mPhone.isInEcm()) {
83 Log.i(TAG, "ECMModeExitDialog launched - isInEcm: false" + " phone:" + mPhone);
Santos Cordon7d4ddf62013-07-10 11:58:08 -070084 finish();
Yorke Lee34a72cb2014-10-12 13:17:04 -070085 return;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070086 }
Brad Ebinger6d4ef742018-02-07 10:59:33 -080087 Log.i(TAG, "ECMModeExitDialog launched - isInEcm: true" + " phone:" + mPhone);
Santos Cordon7d4ddf62013-07-10 11:58:08 -070088
89 mHandler = new Handler();
90
91 // Start thread that will wait for the connection completion so that it can get
92 // timeout value from the service
93 Thread waitForConnectionCompleteThread = new Thread(null, mTask,
94 "EcmExitDialogWaitThread");
95 waitForConnectionCompleteThread.start();
96
97 // Register ECM timer reset notfication
Santos Cordon7d4ddf62013-07-10 11:58:08 -070098 mPhone.registerForEcmTimerReset(mTimerResetHandler, ECM_TIMER_RESET, null);
99
100 // Register receiver for intent closing the dialog
101 IntentFilter filter = new IntentFilter();
102 filter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
103 registerReceiver(mEcmExitReceiver, filter);
104 }
105
106 @Override
Jordan Liu1cfab0d2019-09-27 11:17:52 -0700107 public void onResume() {
108 super.onResume();
109 mIsResumed = true;
110 }
111
112 @Override
113 public void onPause() {
114 super.onPause();
115 mIsResumed = false;
116 }
117
118 @Override
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700119 public void onDestroy() {
120 super.onDestroy();
Yorke Lee34a72cb2014-10-12 13:17:04 -0700121 try {
122 unregisterReceiver(mEcmExitReceiver);
123 } catch (IllegalArgumentException e) {
124 // Receiver was never registered - silently ignore.
125 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700126 // Unregister ECM timer reset notification
Yorke Lee34a72cb2014-10-12 13:17:04 -0700127 if (mPhone != null) {
128 mPhone.unregisterForEcmTimerReset(mHandler);
129 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700130 }
131
132 @Override
133 protected void onRestoreInstanceState(Bundle savedInstanceState) {
134 super.onRestoreInstanceState(savedInstanceState);
135 mDialogType = savedInstanceState.getInt("DIALOG_TYPE");
136 }
137
138 @Override
139 protected void onSaveInstanceState(Bundle outState) {
140 super.onSaveInstanceState(outState);
141 outState.putInt("DIALOG_TYPE", mDialogType);
142 }
143
144 /**
145 * Waits until bind to the service completes
146 */
147 private Runnable mTask = new Runnable() {
148 public void run() {
149 Looper.prepare();
150
151 // Bind to the remote service
152 bindService(new Intent(EmergencyCallbackModeExitDialog.this,
153 EmergencyCallbackModeService.class), mConnection, Context.BIND_AUTO_CREATE);
154
155 // Wait for bind to finish
156 synchronized (EmergencyCallbackModeExitDialog.this) {
157 try {
158 if (mService == null) {
159 EmergencyCallbackModeExitDialog.this.wait();
160 }
161 } catch (InterruptedException e) {
162 Log.d("ECM", "EmergencyCallbackModeExitDialog InterruptedException: "
163 + e.getMessage());
164 e.printStackTrace();
165 }
166 }
167
168 // Get timeout value and call state from the service
169 if (mService != null) {
170 mEcmTimeout = mService.getEmergencyCallbackModeTimeout();
171 mInEmergencyCall = mService.getEmergencyCallbackModeCallState();
Yorke Lee34a72cb2014-10-12 13:17:04 -0700172 try {
173 // Unbind from remote service
174 unbindService(mConnection);
175 } catch (IllegalArgumentException e) {
176 // Failed to unbind from service. Don't crash as this brings down the entire
177 // radio.
178 Log.w(TAG, "Failed to unbind from EmergencyCallbackModeService");
179 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700180 }
181
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700182 // Show dialog
183 mHandler.post(new Runnable() {
184 public void run() {
185 showEmergencyCallbackModeExitDialog();
186 }
187 });
188 }
189 };
190
191 /**
192 * Shows Emergency Callback Mode dialog and starts countdown timer
193 */
194 private void showEmergencyCallbackModeExitDialog() {
Josh Hou704c1f92020-05-28 20:54:29 +0800195 if (isDestroyed()) {
Yorke Lee34a72cb2014-10-12 13:17:04 -0700196 Log.w(TAG, "Tried to show dialog, but activity was already finished");
197 return;
198 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700199 if(mInEmergencyCall) {
200 mDialogType = EXIT_ECM_IN_EMERGENCY_CALL_DIALOG;
201 showDialog(EXIT_ECM_IN_EMERGENCY_CALL_DIALOG);
202 } else {
203 if (getIntent().getAction().equals(
204 TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS)) {
205 mDialogType = EXIT_ECM_BLOCK_OTHERS;
206 showDialog(EXIT_ECM_BLOCK_OTHERS);
207 } else if (getIntent().getAction().equals(ACTION_SHOW_ECM_EXIT_DIALOG)) {
208 mDialogType = EXIT_ECM_DIALOG;
209 showDialog(EXIT_ECM_DIALOG);
210 }
211
212 mTimer = new CountDownTimer(mEcmTimeout, 1000) {
213 @Override
214 public void onTick(long millisUntilFinished) {
215 CharSequence text = getDialogText(millisUntilFinished);
216 mAlertDialog.setMessage(text);
217 }
218
219 @Override
220 public void onFinish() {
221 //Do nothing
222 }
223 }.start();
224 }
225 }
226
227 /**
228 * Creates dialog that enables users to exit Emergency Callback Mode
229 */
230 @Override
231 protected Dialog onCreateDialog(int id) {
232 switch (id) {
233 case EXIT_ECM_BLOCK_OTHERS:
234 case EXIT_ECM_DIALOG:
235 CharSequence text = getDialogText(mEcmTimeout);
Brad Ebinger1a3fa362018-04-19 13:43:31 -0700236 mAlertDialog = new AlertDialog.Builder(EmergencyCallbackModeExitDialog.this,
237 android.R.style.Theme_DeviceDefault_Dialog_Alert)
Tyler Gunn625eb0b2014-08-27 20:37:32 -0700238 .setIcon(R.drawable.ic_emergency_callback_mode)
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700239 .setTitle(R.string.phone_in_ecm_notification_title)
240 .setMessage(text)
241 .setPositiveButton(R.string.alert_dialog_yes,
242 new DialogInterface.OnClickListener() {
243 public void onClick(DialogInterface dialog,int whichButton) {
244 // User clicked Yes. Exit Emergency Callback Mode.
245 mPhone.exitEmergencyCallbackMode();
246
247 // Show progress dialog
248 showDialog(EXIT_ECM_PROGRESS_DIALOG);
249 mTimer.cancel();
250 }
251 })
252 .setNegativeButton(R.string.alert_dialog_no,
253 new DialogInterface.OnClickListener() {
254 public void onClick(DialogInterface dialog, int whichButton) {
255 // User clicked No
Pengquan Meng252acb32018-10-11 17:16:25 -0700256 setResult(RESULT_CANCELED);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700257 finish();
258 }
259 }).create();
Li Wei65667ea2017-08-02 16:06:59 +0800260 mAlertDialog.setOnCancelListener(this);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700261 return mAlertDialog;
262
263 case EXIT_ECM_IN_EMERGENCY_CALL_DIALOG:
Brad Ebinger1a3fa362018-04-19 13:43:31 -0700264 mAlertDialog = new AlertDialog.Builder(EmergencyCallbackModeExitDialog.this,
265 android.R.style.Theme_DeviceDefault_Dialog_Alert)
Tyler Gunn625eb0b2014-08-27 20:37:32 -0700266 .setIcon(R.drawable.ic_emergency_callback_mode)
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700267 .setTitle(R.string.phone_in_ecm_notification_title)
268 .setMessage(R.string.alert_dialog_in_ecm_call)
269 .setNeutralButton(R.string.alert_dialog_dismiss,
270 new DialogInterface.OnClickListener() {
271 public void onClick(DialogInterface dialog, int whichButton) {
272 // User clicked Dismiss
Pengquan Meng252acb32018-10-11 17:16:25 -0700273 setResult(RESULT_CANCELED);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700274 finish();
275 }
276 }).create();
Li Wei65667ea2017-08-02 16:06:59 +0800277 mAlertDialog.setOnCancelListener(this);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700278 return mAlertDialog;
279
280 case EXIT_ECM_PROGRESS_DIALOG:
281 mProgressDialog = new ProgressDialog(EmergencyCallbackModeExitDialog.this);
282 mProgressDialog.setMessage(getText(R.string.progress_dialog_exiting_ecm));
283 mProgressDialog.setIndeterminate(true);
284 mProgressDialog.setCancelable(false);
285 return mProgressDialog;
286
287 default:
288 return null;
289 }
290 }
291
292 /**
293 * Returns dialog box text with updated timeout value
294 */
295 private CharSequence getDialogText(long millisUntilFinished) {
296 // Format time
297 int minutes = (int)(millisUntilFinished / 60000);
298 String time = String.format("%d:%02d", minutes,
299 (millisUntilFinished % 60000) / 1000);
300
301 switch (mDialogType) {
302 case EXIT_ECM_BLOCK_OTHERS:
303 return String.format(getResources().getQuantityText(
304 R.plurals.alert_dialog_not_avaialble_in_ecm, minutes).toString(), time);
305 case EXIT_ECM_DIALOG:
Wei Huang821f3d92019-04-11 11:19:13 +0900306 boolean shouldRestrictData = mPhone.getImsPhone() != null
307 && mPhone.getImsPhone().isInImsEcm();
308 return String.format(getResources().getQuantityText(
309 // During IMS ECM, data restriction hint should be removed.
310 shouldRestrictData
311 ? R.plurals.alert_dialog_exit_ecm_without_data_restriction_hint
312 : R.plurals.alert_dialog_exit_ecm,
313 minutes).toString(), time);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700314 }
315 return null;
316 }
317
318 /**
Li Wei65667ea2017-08-02 16:06:59 +0800319 * Closes activity when dialog is canceled
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700320 */
Yorke Lee34a72cb2014-10-12 13:17:04 -0700321 @Override
Li Wei65667ea2017-08-02 16:06:59 +0800322 public void onCancel(DialogInterface dialog) {
Pengquan Meng252acb32018-10-11 17:16:25 -0700323 EmergencyCallbackModeExitDialog.this.setResult(RESULT_CANCELED);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700324 finish();
325 }
326
327 /**
328 * Listens for Emergency Callback Mode state change intents
329 */
330 private BroadcastReceiver mEcmExitReceiver = new BroadcastReceiver() {
331 @Override
332 public void onReceive(Context context, Intent intent) {
333 // Received exit Emergency Callback Mode notification close all dialogs
334 if (intent.getAction().equals(
335 TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) {
Brad Ebinger3b3c30a2020-03-18 13:59:44 -0700336 // Cancel if the sticky broadcast extra for whether or not we are in ECM is false.
337 if (!intent.getBooleanExtra(TelephonyManager.EXTRA_PHONE_IN_ECM_STATE, false)) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700338 if (mAlertDialog != null)
339 mAlertDialog.dismiss();
340 if (mProgressDialog != null)
341 mProgressDialog.dismiss();
Pengquan Meng252acb32018-10-11 17:16:25 -0700342 EmergencyCallbackModeExitDialog.this.setResult(RESULT_OK);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700343 finish();
344 }
345 }
346 }
347 };
348
349 /**
350 * Class for interacting with the interface of the service
351 */
352 private ServiceConnection mConnection = new ServiceConnection() {
353 public void onServiceConnected(ComponentName className, IBinder service) {
354 mService = ((EmergencyCallbackModeService.LocalBinder)service).getService();
355 // Notify thread that connection is ready
356 synchronized (EmergencyCallbackModeExitDialog.this) {
357 EmergencyCallbackModeExitDialog.this.notify();
358 }
359 }
360
361 public void onServiceDisconnected(ComponentName className) {
362 mService = null;
363 }
364 };
365
366 /**
367 * Class for receiving framework timer reset notifications
368 */
369 private Handler mTimerResetHandler = new Handler () {
370 public void handleMessage(Message msg) {
371 switch (msg.what) {
372 case ECM_TIMER_RESET:
373 if(!((Boolean)((AsyncResult) msg.obj).result).booleanValue()) {
Pengquan Meng252acb32018-10-11 17:16:25 -0700374 EmergencyCallbackModeExitDialog.this.setResult(RESULT_CANCELED);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700375 finish();
376 }
377 break;
378 }
379 }
380 };
381}