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