blob: 765c52da128c93749d93c470cbfc2e5a79404eaf [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;
20import android.app.Dialog;
21import android.app.ProgressDialog;
22import android.app.AlertDialog;
23import 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;
31import android.content.res.Resources;
32import android.os.AsyncResult;
33import android.os.Bundle;
34import android.os.CountDownTimer;
35import android.os.Handler;
36import android.os.IBinder;
37import android.os.Looper;
38import android.os.Message;
39import android.os.SystemProperties;
40import android.util.Log;
41
42import com.android.internal.telephony.Phone;
43import com.android.internal.telephony.TelephonyIntents;
44import com.android.internal.telephony.TelephonyProperties;
45
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";
58 /** Used to get the users choice from the return Intent's extra */
59 public static final String EXTRA_EXIT_ECM_RESULT = "exit_ecm_result";
60
61 public static final int EXIT_ECM_BLOCK_OTHERS = 1;
62 public static final int EXIT_ECM_DIALOG = 2;
63 public static final int EXIT_ECM_PROGRESS_DIALOG = 3;
64 public static final int EXIT_ECM_IN_EMERGENCY_CALL_DIALOG = 4;
65
66 AlertDialog mAlertDialog = null;
67 ProgressDialog mProgressDialog = null;
68 CountDownTimer mTimer = null;
69 EmergencyCallbackModeService mService = null;
70 Handler mHandler = null;
71 int mDialogType = 0;
72 long mEcmTimeout = 0;
73 private boolean mInEmergencyCall = false;
74 private static final int ECM_TIMER_RESET = 1;
75 private Phone mPhone = null;
76
77 @Override
78 public void onCreate(Bundle savedInstanceState) {
79 super.onCreate(savedInstanceState);
80
Sandeep Kuntade73a6a2014-10-15 18:45:56 +053081 mPhone = PhoneGlobals.getInstance().getPhoneInEcm();
Santos Cordon7d4ddf62013-07-10 11:58:08 -070082 // Check if phone is in Emergency Callback Mode. If not, exit.
shuoqfef36a32017-01-10 13:02:18 -080083 final boolean isInEcm = mPhone.isInEcm();
Sandeep Kuntade73a6a2014-10-15 18:45:56 +053084 Log.i(TAG, "ECMModeExitDialog launched - isInEcm: " + isInEcm + " phone:" + mPhone);
85 if (mPhone == null || !isInEcm) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -070086 finish();
Yorke Lee34a72cb2014-10-12 13:17:04 -070087 return;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070088 }
89
90 mHandler = new Handler();
91
92 // Start thread that will wait for the connection completion so that it can get
93 // timeout value from the service
94 Thread waitForConnectionCompleteThread = new Thread(null, mTask,
95 "EcmExitDialogWaitThread");
96 waitForConnectionCompleteThread.start();
97
98 // Register ECM timer reset notfication
Santos Cordon7d4ddf62013-07-10 11:58:08 -070099 mPhone.registerForEcmTimerReset(mTimerResetHandler, ECM_TIMER_RESET, null);
100
101 // Register receiver for intent closing the dialog
102 IntentFilter filter = new IntentFilter();
103 filter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
104 registerReceiver(mEcmExitReceiver, filter);
105 }
106
107 @Override
108 public void onDestroy() {
109 super.onDestroy();
Yorke Lee34a72cb2014-10-12 13:17:04 -0700110 try {
111 unregisterReceiver(mEcmExitReceiver);
112 } catch (IllegalArgumentException e) {
113 // Receiver was never registered - silently ignore.
114 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700115 // Unregister ECM timer reset notification
Yorke Lee34a72cb2014-10-12 13:17:04 -0700116 if (mPhone != null) {
117 mPhone.unregisterForEcmTimerReset(mHandler);
118 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700119 }
120
121 @Override
122 protected void onRestoreInstanceState(Bundle savedInstanceState) {
123 super.onRestoreInstanceState(savedInstanceState);
124 mDialogType = savedInstanceState.getInt("DIALOG_TYPE");
125 }
126
127 @Override
128 protected void onSaveInstanceState(Bundle outState) {
129 super.onSaveInstanceState(outState);
130 outState.putInt("DIALOG_TYPE", mDialogType);
131 }
132
133 /**
134 * Waits until bind to the service completes
135 */
136 private Runnable mTask = new Runnable() {
137 public void run() {
138 Looper.prepare();
139
140 // Bind to the remote service
141 bindService(new Intent(EmergencyCallbackModeExitDialog.this,
142 EmergencyCallbackModeService.class), mConnection, Context.BIND_AUTO_CREATE);
143
144 // Wait for bind to finish
145 synchronized (EmergencyCallbackModeExitDialog.this) {
146 try {
147 if (mService == null) {
148 EmergencyCallbackModeExitDialog.this.wait();
149 }
150 } catch (InterruptedException e) {
151 Log.d("ECM", "EmergencyCallbackModeExitDialog InterruptedException: "
152 + e.getMessage());
153 e.printStackTrace();
154 }
155 }
156
157 // Get timeout value and call state from the service
158 if (mService != null) {
159 mEcmTimeout = mService.getEmergencyCallbackModeTimeout();
160 mInEmergencyCall = mService.getEmergencyCallbackModeCallState();
Yorke Lee34a72cb2014-10-12 13:17:04 -0700161 try {
162 // Unbind from remote service
163 unbindService(mConnection);
164 } catch (IllegalArgumentException e) {
165 // Failed to unbind from service. Don't crash as this brings down the entire
166 // radio.
167 Log.w(TAG, "Failed to unbind from EmergencyCallbackModeService");
168 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700169 }
170
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700171 // Show dialog
172 mHandler.post(new Runnable() {
173 public void run() {
174 showEmergencyCallbackModeExitDialog();
175 }
176 });
177 }
178 };
179
180 /**
181 * Shows Emergency Callback Mode dialog and starts countdown timer
182 */
183 private void showEmergencyCallbackModeExitDialog() {
Yorke Lee34a72cb2014-10-12 13:17:04 -0700184 if (!this.isResumed()) {
185 Log.w(TAG, "Tried to show dialog, but activity was already finished");
186 return;
187 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700188 if(mInEmergencyCall) {
189 mDialogType = EXIT_ECM_IN_EMERGENCY_CALL_DIALOG;
190 showDialog(EXIT_ECM_IN_EMERGENCY_CALL_DIALOG);
191 } else {
192 if (getIntent().getAction().equals(
193 TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS)) {
194 mDialogType = EXIT_ECM_BLOCK_OTHERS;
195 showDialog(EXIT_ECM_BLOCK_OTHERS);
196 } else if (getIntent().getAction().equals(ACTION_SHOW_ECM_EXIT_DIALOG)) {
197 mDialogType = EXIT_ECM_DIALOG;
198 showDialog(EXIT_ECM_DIALOG);
199 }
200
201 mTimer = new CountDownTimer(mEcmTimeout, 1000) {
202 @Override
203 public void onTick(long millisUntilFinished) {
204 CharSequence text = getDialogText(millisUntilFinished);
205 mAlertDialog.setMessage(text);
206 }
207
208 @Override
209 public void onFinish() {
210 //Do nothing
211 }
212 }.start();
213 }
214 }
215
216 /**
217 * Creates dialog that enables users to exit Emergency Callback Mode
218 */
219 @Override
220 protected Dialog onCreateDialog(int id) {
221 switch (id) {
222 case EXIT_ECM_BLOCK_OTHERS:
223 case EXIT_ECM_DIALOG:
224 CharSequence text = getDialogText(mEcmTimeout);
225 mAlertDialog = new AlertDialog.Builder(EmergencyCallbackModeExitDialog.this)
Tyler Gunn625eb0b2014-08-27 20:37:32 -0700226 .setIcon(R.drawable.ic_emergency_callback_mode)
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700227 .setTitle(R.string.phone_in_ecm_notification_title)
228 .setMessage(text)
229 .setPositiveButton(R.string.alert_dialog_yes,
230 new DialogInterface.OnClickListener() {
231 public void onClick(DialogInterface dialog,int whichButton) {
232 // User clicked Yes. Exit Emergency Callback Mode.
233 mPhone.exitEmergencyCallbackMode();
234
235 // Show progress dialog
236 showDialog(EXIT_ECM_PROGRESS_DIALOG);
237 mTimer.cancel();
238 }
239 })
240 .setNegativeButton(R.string.alert_dialog_no,
241 new DialogInterface.OnClickListener() {
242 public void onClick(DialogInterface dialog, int whichButton) {
243 // User clicked No
244 setResult(RESULT_OK, (new Intent()).putExtra(
245 EXTRA_EXIT_ECM_RESULT, false));
246 finish();
247 }
248 }).create();
Li Wei65667ea2017-08-02 16:06:59 +0800249 mAlertDialog.setOnCancelListener(this);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700250 return mAlertDialog;
251
252 case EXIT_ECM_IN_EMERGENCY_CALL_DIALOG:
253 mAlertDialog = new AlertDialog.Builder(EmergencyCallbackModeExitDialog.this)
Tyler Gunn625eb0b2014-08-27 20:37:32 -0700254 .setIcon(R.drawable.ic_emergency_callback_mode)
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700255 .setTitle(R.string.phone_in_ecm_notification_title)
256 .setMessage(R.string.alert_dialog_in_ecm_call)
257 .setNeutralButton(R.string.alert_dialog_dismiss,
258 new DialogInterface.OnClickListener() {
259 public void onClick(DialogInterface dialog, int whichButton) {
260 // User clicked Dismiss
261 setResult(RESULT_OK, (new Intent()).putExtra(
262 EXTRA_EXIT_ECM_RESULT, false));
263 finish();
264 }
265 }).create();
Li Wei65667ea2017-08-02 16:06:59 +0800266 mAlertDialog.setOnCancelListener(this);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700267 return mAlertDialog;
268
269 case EXIT_ECM_PROGRESS_DIALOG:
270 mProgressDialog = new ProgressDialog(EmergencyCallbackModeExitDialog.this);
271 mProgressDialog.setMessage(getText(R.string.progress_dialog_exiting_ecm));
272 mProgressDialog.setIndeterminate(true);
273 mProgressDialog.setCancelable(false);
274 return mProgressDialog;
275
276 default:
277 return null;
278 }
279 }
280
281 /**
282 * Returns dialog box text with updated timeout value
283 */
284 private CharSequence getDialogText(long millisUntilFinished) {
285 // Format time
286 int minutes = (int)(millisUntilFinished / 60000);
287 String time = String.format("%d:%02d", minutes,
288 (millisUntilFinished % 60000) / 1000);
289
290 switch (mDialogType) {
291 case EXIT_ECM_BLOCK_OTHERS:
292 return String.format(getResources().getQuantityText(
293 R.plurals.alert_dialog_not_avaialble_in_ecm, minutes).toString(), time);
294 case EXIT_ECM_DIALOG:
295 return String.format(getResources().getQuantityText(R.plurals.alert_dialog_exit_ecm,
296 minutes).toString(), time);
297 }
298 return null;
299 }
300
301 /**
Li Wei65667ea2017-08-02 16:06:59 +0800302 * Closes activity when dialog is canceled
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700303 */
Yorke Lee34a72cb2014-10-12 13:17:04 -0700304 @Override
Li Wei65667ea2017-08-02 16:06:59 +0800305 public void onCancel(DialogInterface dialog) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700306 EmergencyCallbackModeExitDialog.this.setResult(RESULT_OK, (new Intent())
307 .putExtra(EXTRA_EXIT_ECM_RESULT, false));
308 finish();
309 }
310
311 /**
312 * Listens for Emergency Callback Mode state change intents
313 */
314 private BroadcastReceiver mEcmExitReceiver = new BroadcastReceiver() {
315 @Override
316 public void onReceive(Context context, Intent intent) {
317 // Received exit Emergency Callback Mode notification close all dialogs
318 if (intent.getAction().equals(
319 TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) {
320 if (intent.getBooleanExtra("phoneinECMState", false) == false) {
321 if (mAlertDialog != null)
322 mAlertDialog.dismiss();
323 if (mProgressDialog != null)
324 mProgressDialog.dismiss();
325 EmergencyCallbackModeExitDialog.this.setResult(RESULT_OK, (new Intent())
326 .putExtra(EXTRA_EXIT_ECM_RESULT, true));
327 finish();
328 }
329 }
330 }
331 };
332
333 /**
334 * Class for interacting with the interface of the service
335 */
336 private ServiceConnection mConnection = new ServiceConnection() {
337 public void onServiceConnected(ComponentName className, IBinder service) {
338 mService = ((EmergencyCallbackModeService.LocalBinder)service).getService();
339 // Notify thread that connection is ready
340 synchronized (EmergencyCallbackModeExitDialog.this) {
341 EmergencyCallbackModeExitDialog.this.notify();
342 }
343 }
344
345 public void onServiceDisconnected(ComponentName className) {
346 mService = null;
347 }
348 };
349
350 /**
351 * Class for receiving framework timer reset notifications
352 */
353 private Handler mTimerResetHandler = new Handler () {
354 public void handleMessage(Message msg) {
355 switch (msg.what) {
356 case ECM_TIMER_RESET:
357 if(!((Boolean)((AsyncResult) msg.obj).result).booleanValue()) {
358 EmergencyCallbackModeExitDialog.this.setResult(RESULT_OK, (new Intent())
359 .putExtra(EXTRA_EXIT_ECM_RESULT, false));
360 finish();
361 }
362 break;
363 }
364 }
365 };
366}