blob: 12106273735bb6bf1dd0b75c5f6ff053b0799ad2 [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;
Brad Ebinger3b3c30a2020-03-18 13:59:44 -070038import android.telephony.TelephonyManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070039import android.util.Log;
40
41import com.android.internal.telephony.Phone;
42import com.android.internal.telephony.TelephonyIntents;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070043
44/**
45 * Displays dialog that enables users to exit Emergency Callback Mode
46 *
47 * @see EmergencyCallbackModeService
48 */
Li Wei65667ea2017-08-02 16:06:59 +080049public class EmergencyCallbackModeExitDialog extends Activity implements OnCancelListener {
Santos Cordon7d4ddf62013-07-10 11:58:08 -070050
Yorke Lee34a72cb2014-10-12 13:17:04 -070051 private static final String TAG = "EmergencyCallbackMode";
52
Santos Cordon7d4ddf62013-07-10 11:58:08 -070053 /** Intent to trigger the Emergency Callback Mode exit dialog */
54 static final String ACTION_SHOW_ECM_EXIT_DIALOG =
55 "com.android.phone.action.ACTION_SHOW_ECM_EXIT_DIALOG";
Santos Cordon7d4ddf62013-07-10 11:58:08 -070056
57 public static final int EXIT_ECM_BLOCK_OTHERS = 1;
58 public static final int EXIT_ECM_DIALOG = 2;
59 public static final int EXIT_ECM_PROGRESS_DIALOG = 3;
60 public static final int EXIT_ECM_IN_EMERGENCY_CALL_DIALOG = 4;
61
62 AlertDialog mAlertDialog = null;
63 ProgressDialog mProgressDialog = null;
64 CountDownTimer mTimer = null;
65 EmergencyCallbackModeService mService = null;
66 Handler mHandler = null;
67 int mDialogType = 0;
68 long mEcmTimeout = 0;
69 private boolean mInEmergencyCall = false;
70 private static final int ECM_TIMER_RESET = 1;
71 private Phone mPhone = null;
Jordan Liu1cfab0d2019-09-27 11:17:52 -070072 private boolean mIsResumed = false;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070073
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
Jordan Liu1cfab0d2019-09-27 11:17:52 -0700105 public void onResume() {
106 super.onResume();
107 mIsResumed = true;
108 }
109
110 @Override
111 public void onPause() {
112 super.onPause();
113 mIsResumed = false;
114 }
115
116 @Override
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700117 public void onDestroy() {
118 super.onDestroy();
Yorke Lee34a72cb2014-10-12 13:17:04 -0700119 try {
120 unregisterReceiver(mEcmExitReceiver);
121 } catch (IllegalArgumentException e) {
122 // Receiver was never registered - silently ignore.
123 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700124 // Unregister ECM timer reset notification
Yorke Lee34a72cb2014-10-12 13:17:04 -0700125 if (mPhone != null) {
126 mPhone.unregisterForEcmTimerReset(mHandler);
127 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700128 }
129
130 @Override
131 protected void onRestoreInstanceState(Bundle savedInstanceState) {
132 super.onRestoreInstanceState(savedInstanceState);
133 mDialogType = savedInstanceState.getInt("DIALOG_TYPE");
134 }
135
136 @Override
137 protected void onSaveInstanceState(Bundle outState) {
138 super.onSaveInstanceState(outState);
139 outState.putInt("DIALOG_TYPE", mDialogType);
140 }
141
142 /**
143 * Waits until bind to the service completes
144 */
145 private Runnable mTask = new Runnable() {
146 public void run() {
147 Looper.prepare();
148
149 // Bind to the remote service
150 bindService(new Intent(EmergencyCallbackModeExitDialog.this,
151 EmergencyCallbackModeService.class), mConnection, Context.BIND_AUTO_CREATE);
152
153 // Wait for bind to finish
154 synchronized (EmergencyCallbackModeExitDialog.this) {
155 try {
156 if (mService == null) {
157 EmergencyCallbackModeExitDialog.this.wait();
158 }
159 } catch (InterruptedException e) {
160 Log.d("ECM", "EmergencyCallbackModeExitDialog InterruptedException: "
161 + e.getMessage());
162 e.printStackTrace();
163 }
164 }
165
166 // Get timeout value and call state from the service
167 if (mService != null) {
168 mEcmTimeout = mService.getEmergencyCallbackModeTimeout();
169 mInEmergencyCall = mService.getEmergencyCallbackModeCallState();
Yorke Lee34a72cb2014-10-12 13:17:04 -0700170 try {
171 // Unbind from remote service
172 unbindService(mConnection);
173 } catch (IllegalArgumentException e) {
174 // Failed to unbind from service. Don't crash as this brings down the entire
175 // radio.
176 Log.w(TAG, "Failed to unbind from EmergencyCallbackModeService");
177 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700178 }
179
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700180 // Show dialog
181 mHandler.post(new Runnable() {
182 public void run() {
183 showEmergencyCallbackModeExitDialog();
184 }
185 });
186 }
187 };
188
189 /**
190 * Shows Emergency Callback Mode dialog and starts countdown timer
191 */
192 private void showEmergencyCallbackModeExitDialog() {
Jordan Liu1cfab0d2019-09-27 11:17:52 -0700193 if (!mIsResumed) {
Yorke Lee34a72cb2014-10-12 13:17:04 -0700194 Log.w(TAG, "Tried to show dialog, but activity was already finished");
195 return;
196 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700197 if(mInEmergencyCall) {
198 mDialogType = EXIT_ECM_IN_EMERGENCY_CALL_DIALOG;
199 showDialog(EXIT_ECM_IN_EMERGENCY_CALL_DIALOG);
200 } else {
201 if (getIntent().getAction().equals(
202 TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS)) {
203 mDialogType = EXIT_ECM_BLOCK_OTHERS;
204 showDialog(EXIT_ECM_BLOCK_OTHERS);
205 } else if (getIntent().getAction().equals(ACTION_SHOW_ECM_EXIT_DIALOG)) {
206 mDialogType = EXIT_ECM_DIALOG;
207 showDialog(EXIT_ECM_DIALOG);
208 }
209
210 mTimer = new CountDownTimer(mEcmTimeout, 1000) {
211 @Override
212 public void onTick(long millisUntilFinished) {
213 CharSequence text = getDialogText(millisUntilFinished);
214 mAlertDialog.setMessage(text);
215 }
216
217 @Override
218 public void onFinish() {
219 //Do nothing
220 }
221 }.start();
222 }
223 }
224
225 /**
226 * Creates dialog that enables users to exit Emergency Callback Mode
227 */
228 @Override
229 protected Dialog onCreateDialog(int id) {
230 switch (id) {
231 case EXIT_ECM_BLOCK_OTHERS:
232 case EXIT_ECM_DIALOG:
233 CharSequence text = getDialogText(mEcmTimeout);
Brad Ebinger1a3fa362018-04-19 13:43:31 -0700234 mAlertDialog = new AlertDialog.Builder(EmergencyCallbackModeExitDialog.this,
235 android.R.style.Theme_DeviceDefault_Dialog_Alert)
Tyler Gunn625eb0b2014-08-27 20:37:32 -0700236 .setIcon(R.drawable.ic_emergency_callback_mode)
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700237 .setTitle(R.string.phone_in_ecm_notification_title)
238 .setMessage(text)
239 .setPositiveButton(R.string.alert_dialog_yes,
240 new DialogInterface.OnClickListener() {
241 public void onClick(DialogInterface dialog,int whichButton) {
242 // User clicked Yes. Exit Emergency Callback Mode.
243 mPhone.exitEmergencyCallbackMode();
244
245 // Show progress dialog
246 showDialog(EXIT_ECM_PROGRESS_DIALOG);
247 mTimer.cancel();
248 }
249 })
250 .setNegativeButton(R.string.alert_dialog_no,
251 new DialogInterface.OnClickListener() {
252 public void onClick(DialogInterface dialog, int whichButton) {
253 // User clicked No
Pengquan Meng252acb32018-10-11 17:16:25 -0700254 setResult(RESULT_CANCELED);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700255 finish();
256 }
257 }).create();
Li Wei65667ea2017-08-02 16:06:59 +0800258 mAlertDialog.setOnCancelListener(this);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700259 return mAlertDialog;
260
261 case EXIT_ECM_IN_EMERGENCY_CALL_DIALOG:
Brad Ebinger1a3fa362018-04-19 13:43:31 -0700262 mAlertDialog = new AlertDialog.Builder(EmergencyCallbackModeExitDialog.this,
263 android.R.style.Theme_DeviceDefault_Dialog_Alert)
Tyler Gunn625eb0b2014-08-27 20:37:32 -0700264 .setIcon(R.drawable.ic_emergency_callback_mode)
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700265 .setTitle(R.string.phone_in_ecm_notification_title)
266 .setMessage(R.string.alert_dialog_in_ecm_call)
267 .setNeutralButton(R.string.alert_dialog_dismiss,
268 new DialogInterface.OnClickListener() {
269 public void onClick(DialogInterface dialog, int whichButton) {
270 // User clicked Dismiss
Pengquan Meng252acb32018-10-11 17:16:25 -0700271 setResult(RESULT_CANCELED);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700272 finish();
273 }
274 }).create();
Li Wei65667ea2017-08-02 16:06:59 +0800275 mAlertDialog.setOnCancelListener(this);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700276 return mAlertDialog;
277
278 case EXIT_ECM_PROGRESS_DIALOG:
279 mProgressDialog = new ProgressDialog(EmergencyCallbackModeExitDialog.this);
280 mProgressDialog.setMessage(getText(R.string.progress_dialog_exiting_ecm));
281 mProgressDialog.setIndeterminate(true);
282 mProgressDialog.setCancelable(false);
283 return mProgressDialog;
284
285 default:
286 return null;
287 }
288 }
289
290 /**
291 * Returns dialog box text with updated timeout value
292 */
293 private CharSequence getDialogText(long millisUntilFinished) {
294 // Format time
295 int minutes = (int)(millisUntilFinished / 60000);
296 String time = String.format("%d:%02d", minutes,
297 (millisUntilFinished % 60000) / 1000);
298
299 switch (mDialogType) {
300 case EXIT_ECM_BLOCK_OTHERS:
301 return String.format(getResources().getQuantityText(
302 R.plurals.alert_dialog_not_avaialble_in_ecm, minutes).toString(), time);
303 case EXIT_ECM_DIALOG:
Wei Huang821f3d92019-04-11 11:19:13 +0900304 boolean shouldRestrictData = mPhone.getImsPhone() != null
305 && mPhone.getImsPhone().isInImsEcm();
306 return String.format(getResources().getQuantityText(
307 // During IMS ECM, data restriction hint should be removed.
308 shouldRestrictData
309 ? R.plurals.alert_dialog_exit_ecm_without_data_restriction_hint
310 : R.plurals.alert_dialog_exit_ecm,
311 minutes).toString(), time);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700312 }
313 return null;
314 }
315
316 /**
Li Wei65667ea2017-08-02 16:06:59 +0800317 * Closes activity when dialog is canceled
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700318 */
Yorke Lee34a72cb2014-10-12 13:17:04 -0700319 @Override
Li Wei65667ea2017-08-02 16:06:59 +0800320 public void onCancel(DialogInterface dialog) {
Pengquan Meng252acb32018-10-11 17:16:25 -0700321 EmergencyCallbackModeExitDialog.this.setResult(RESULT_CANCELED);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700322 finish();
323 }
324
325 /**
326 * Listens for Emergency Callback Mode state change intents
327 */
328 private BroadcastReceiver mEcmExitReceiver = new BroadcastReceiver() {
329 @Override
330 public void onReceive(Context context, Intent intent) {
331 // Received exit Emergency Callback Mode notification close all dialogs
332 if (intent.getAction().equals(
333 TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) {
Brad Ebinger3b3c30a2020-03-18 13:59:44 -0700334 // Cancel if the sticky broadcast extra for whether or not we are in ECM is false.
335 if (!intent.getBooleanExtra(TelephonyManager.EXTRA_PHONE_IN_ECM_STATE, false)) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700336 if (mAlertDialog != null)
337 mAlertDialog.dismiss();
338 if (mProgressDialog != null)
339 mProgressDialog.dismiss();
Pengquan Meng252acb32018-10-11 17:16:25 -0700340 EmergencyCallbackModeExitDialog.this.setResult(RESULT_OK);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700341 finish();
342 }
343 }
344 }
345 };
346
347 /**
348 * Class for interacting with the interface of the service
349 */
350 private ServiceConnection mConnection = new ServiceConnection() {
351 public void onServiceConnected(ComponentName className, IBinder service) {
352 mService = ((EmergencyCallbackModeService.LocalBinder)service).getService();
353 // Notify thread that connection is ready
354 synchronized (EmergencyCallbackModeExitDialog.this) {
355 EmergencyCallbackModeExitDialog.this.notify();
356 }
357 }
358
359 public void onServiceDisconnected(ComponentName className) {
360 mService = null;
361 }
362 };
363
364 /**
365 * Class for receiving framework timer reset notifications
366 */
367 private Handler mTimerResetHandler = new Handler () {
368 public void handleMessage(Message msg) {
369 switch (msg.what) {
370 case ECM_TIMER_RESET:
371 if(!((Boolean)((AsyncResult) msg.obj).result).booleanValue()) {
Pengquan Meng252acb32018-10-11 17:16:25 -0700372 EmergencyCallbackModeExitDialog.this.setResult(RESULT_CANCELED);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700373 finish();
374 }
375 break;
376 }
377 }
378 };
379}