blob: fc0e513a01865e0d226cdbd76639f4332a92bd8c [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;
Aishwarya Mallampati6ad54362022-01-22 01:08:21 +000033import android.icu.text.MessageFormat;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070034import android.os.AsyncResult;
35import android.os.Bundle;
36import android.os.CountDownTimer;
37import android.os.Handler;
38import android.os.IBinder;
39import android.os.Looper;
40import android.os.Message;
Brad Ebinger3b3c30a2020-03-18 13:59:44 -070041import android.telephony.TelephonyManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070042import android.util.Log;
43
44import com.android.internal.telephony.Phone;
45import com.android.internal.telephony.TelephonyIntents;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070046
Aishwarya Mallampati6ad54362022-01-22 01:08:21 +000047import java.util.HashMap;
48import java.util.Map;
49
Santos Cordon7d4ddf62013-07-10 11:58:08 -070050/**
51 * Displays dialog that enables users to exit Emergency Callback Mode
52 *
53 * @see EmergencyCallbackModeService
54 */
Li Wei65667ea2017-08-02 16:06:59 +080055public class EmergencyCallbackModeExitDialog extends Activity implements OnCancelListener {
Santos Cordon7d4ddf62013-07-10 11:58:08 -070056
Yorke Lee34a72cb2014-10-12 13:17:04 -070057 private static final String TAG = "EmergencyCallbackMode";
58
Santos Cordon7d4ddf62013-07-10 11:58:08 -070059 /** 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";
Santos Cordon7d4ddf62013-07-10 11:58:08 -070062
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;
Jordan Liu1cfab0d2019-09-27 11:17:52 -070078 private boolean mIsResumed = false;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070079
80 @Override
81 public void onCreate(Bundle savedInstanceState) {
82 super.onCreate(savedInstanceState);
Shuo Qian479dd9e2021-02-22 18:32:21 -080083 getWindow().addPrivateFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
Sandeep Kuntade73a6a2014-10-15 18:45:56 +053084 mPhone = PhoneGlobals.getInstance().getPhoneInEcm();
Santos Cordon7d4ddf62013-07-10 11:58:08 -070085 // Check if phone is in Emergency Callback Mode. If not, exit.
Brad Ebinger6d4ef742018-02-07 10:59:33 -080086 if (mPhone == null || !mPhone.isInEcm()) {
87 Log.i(TAG, "ECMModeExitDialog launched - isInEcm: false" + " phone:" + mPhone);
Santos Cordon7d4ddf62013-07-10 11:58:08 -070088 finish();
Yorke Lee34a72cb2014-10-12 13:17:04 -070089 return;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070090 }
Brad Ebinger6d4ef742018-02-07 10:59:33 -080091 Log.i(TAG, "ECMModeExitDialog launched - isInEcm: true" + " phone:" + mPhone);
Santos Cordon7d4ddf62013-07-10 11:58:08 -070092
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
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700102 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
Jordan Liu1cfab0d2019-09-27 11:17:52 -0700111 public void onResume() {
112 super.onResume();
113 mIsResumed = true;
114 }
115
116 @Override
117 public void onPause() {
118 super.onPause();
119 mIsResumed = false;
120 }
121
122 @Override
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700123 public void onDestroy() {
124 super.onDestroy();
Yorke Lee34a72cb2014-10-12 13:17:04 -0700125 try {
126 unregisterReceiver(mEcmExitReceiver);
127 } catch (IllegalArgumentException e) {
128 // Receiver was never registered - silently ignore.
129 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700130 // Unregister ECM timer reset notification
Yorke Lee34a72cb2014-10-12 13:17:04 -0700131 if (mPhone != null) {
132 mPhone.unregisterForEcmTimerReset(mHandler);
133 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700134 }
135
136 @Override
137 protected void onRestoreInstanceState(Bundle savedInstanceState) {
138 super.onRestoreInstanceState(savedInstanceState);
139 mDialogType = savedInstanceState.getInt("DIALOG_TYPE");
140 }
141
142 @Override
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();
Yorke Lee34a72cb2014-10-12 13:17:04 -0700176 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 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700184 }
185
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700186 // 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 */
198 private void showEmergencyCallbackModeExitDialog() {
Josh Hou704c1f92020-05-28 20:54:29 +0800199 if (isDestroyed()) {
Yorke Lee34a72cb2014-10-12 13:17:04 -0700200 Log.w(TAG, "Tried to show dialog, but activity was already finished");
201 return;
202 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700203 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
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);
Brad Ebinger1a3fa362018-04-19 13:43:31 -0700240 mAlertDialog = new AlertDialog.Builder(EmergencyCallbackModeExitDialog.this,
241 android.R.style.Theme_DeviceDefault_Dialog_Alert)
Tyler Gunn625eb0b2014-08-27 20:37:32 -0700242 .setIcon(R.drawable.ic_emergency_callback_mode)
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700243 .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
Pengquan Meng252acb32018-10-11 17:16:25 -0700260 setResult(RESULT_CANCELED);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700261 finish();
262 }
263 }).create();
Li Wei65667ea2017-08-02 16:06:59 +0800264 mAlertDialog.setOnCancelListener(this);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700265 return mAlertDialog;
266
267 case EXIT_ECM_IN_EMERGENCY_CALL_DIALOG:
Brad Ebinger1a3fa362018-04-19 13:43:31 -0700268 mAlertDialog = new AlertDialog.Builder(EmergencyCallbackModeExitDialog.this,
269 android.R.style.Theme_DeviceDefault_Dialog_Alert)
Tyler Gunn625eb0b2014-08-27 20:37:32 -0700270 .setIcon(R.drawable.ic_emergency_callback_mode)
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700271 .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
Pengquan Meng252acb32018-10-11 17:16:25 -0700277 setResult(RESULT_CANCELED);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700278 finish();
279 }
280 }).create();
Li Wei65667ea2017-08-02 16:06:59 +0800281 mAlertDialog.setOnCancelListener(this);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700282 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 */
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);
Aishwarya Mallampati6ad54362022-01-22 01:08:21 +0000304 Map<String, Object> msgArgs = new HashMap<>();
305 msgArgs.put("count", minutes);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700306
307 switch (mDialogType) {
308 case EXIT_ECM_BLOCK_OTHERS:
Aishwarya Mallampati6ad54362022-01-22 01:08:21 +0000309 return MessageFormat.format(getResources().getString(
310 R.string.alert_dialog_not_avaialble_in_ecm, time), msgArgs);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700311 case EXIT_ECM_DIALOG:
Wei Huang821f3d92019-04-11 11:19:13 +0900312 boolean shouldRestrictData = mPhone.getImsPhone() != null
313 && mPhone.getImsPhone().isInImsEcm();
Aishwarya Mallampati6ad54362022-01-22 01:08:21 +0000314 return MessageFormat.format(getResources().getString(
Wei Huang821f3d92019-04-11 11:19:13 +0900315 // During IMS ECM, data restriction hint should be removed.
316 shouldRestrictData
Aishwarya Mallampati6ad54362022-01-22 01:08:21 +0000317 ? R.string.alert_dialog_exit_ecm_without_data_restriction_hint
318 : R.string.alert_dialog_exit_ecm,
319 time), msgArgs);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700320 }
321 return null;
322 }
323
324 /**
Li Wei65667ea2017-08-02 16:06:59 +0800325 * Closes activity when dialog is canceled
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700326 */
Yorke Lee34a72cb2014-10-12 13:17:04 -0700327 @Override
Li Wei65667ea2017-08-02 16:06:59 +0800328 public void onCancel(DialogInterface dialog) {
Pengquan Meng252acb32018-10-11 17:16:25 -0700329 EmergencyCallbackModeExitDialog.this.setResult(RESULT_CANCELED);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700330 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)) {
Brad Ebinger3b3c30a2020-03-18 13:59:44 -0700342 // 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)) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700344 if (mAlertDialog != null)
345 mAlertDialog.dismiss();
346 if (mProgressDialog != null)
347 mProgressDialog.dismiss();
Pengquan Meng252acb32018-10-11 17:16:25 -0700348 EmergencyCallbackModeExitDialog.this.setResult(RESULT_OK);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700349 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()) {
Pengquan Meng252acb32018-10-11 17:16:25 -0700380 EmergencyCallbackModeExitDialog.this.setResult(RESULT_CANCELED);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700381 finish();
382 }
383 break;
384 }
385 }
386 };
387}