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.PhoneFactory; 44 import com.android.internal.telephony.TelephonyIntents; 45 import com.android.internal.telephony.TelephonyProperties; 46 47 /** 48 * Displays dialog that enables users to exit Emergency Callback Mode 49 * 50 * @see EmergencyCallbackModeService 51 */ 52 public class EmergencyCallbackModeExitDialog extends Activity implements OnDismissListener { 53 54 /** Intent to trigger the Emergency Callback Mode exit dialog */ 55 static final String ACTION_SHOW_ECM_EXIT_DIALOG = 56 "com.android.phone.action.ACTION_SHOW_ECM_EXIT_DIALOG"; 57 /** Used to get the users choice from the return Intent's extra */ 58 public static final String EXTRA_EXIT_ECM_RESULT = "exit_ecm_result"; 59 60 public static final int EXIT_ECM_BLOCK_OTHERS = 1; 61 public static final int EXIT_ECM_DIALOG = 2; 62 public static final int EXIT_ECM_PROGRESS_DIALOG = 3; 63 public static final int EXIT_ECM_IN_EMERGENCY_CALL_DIALOG = 4; 64 65 AlertDialog mAlertDialog = null; 66 ProgressDialog mProgressDialog = null; 67 CountDownTimer mTimer = null; 68 EmergencyCallbackModeService mService = null; 69 Handler mHandler = null; 70 int mDialogType = 0; 71 long mEcmTimeout = 0; 72 private boolean mInEmergencyCall = false; 73 private static final int ECM_TIMER_RESET = 1; 74 private Phone mPhone = null; 75 76 @Override onCreate(Bundle savedInstanceState)77 public void onCreate(Bundle savedInstanceState) { 78 super.onCreate(savedInstanceState); 79 80 // Check if phone is in Emergency Callback Mode. If not, exit. 81 if (!Boolean.parseBoolean( 82 SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE))) { 83 finish(); 84 } 85 86 mHandler = new Handler(); 87 88 // Start thread that will wait for the connection completion so that it can get 89 // timeout value from the service 90 Thread waitForConnectionCompleteThread = new Thread(null, mTask, 91 "EcmExitDialogWaitThread"); 92 waitForConnectionCompleteThread.start(); 93 94 // Register ECM timer reset notfication 95 mPhone = PhoneFactory.getDefaultPhone(); 96 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 onDestroy()105 public void onDestroy() { 106 super.onDestroy(); 107 unregisterReceiver(mEcmExitReceiver); 108 // Unregister ECM timer reset notification 109 mPhone.unregisterForEcmTimerReset(mHandler); 110 } 111 112 @Override onRestoreInstanceState(Bundle savedInstanceState)113 protected void onRestoreInstanceState(Bundle savedInstanceState) { 114 super.onRestoreInstanceState(savedInstanceState); 115 mDialogType = savedInstanceState.getInt("DIALOG_TYPE"); 116 } 117 118 @Override onSaveInstanceState(Bundle outState)119 protected void onSaveInstanceState(Bundle outState) { 120 super.onSaveInstanceState(outState); 121 outState.putInt("DIALOG_TYPE", mDialogType); 122 } 123 124 /** 125 * Waits until bind to the service completes 126 */ 127 private Runnable mTask = new Runnable() { 128 public void run() { 129 Looper.prepare(); 130 131 // Bind to the remote service 132 bindService(new Intent(EmergencyCallbackModeExitDialog.this, 133 EmergencyCallbackModeService.class), mConnection, Context.BIND_AUTO_CREATE); 134 135 // Wait for bind to finish 136 synchronized (EmergencyCallbackModeExitDialog.this) { 137 try { 138 if (mService == null) { 139 EmergencyCallbackModeExitDialog.this.wait(); 140 } 141 } catch (InterruptedException e) { 142 Log.d("ECM", "EmergencyCallbackModeExitDialog InterruptedException: " 143 + e.getMessage()); 144 e.printStackTrace(); 145 } 146 } 147 148 // Get timeout value and call state from the service 149 if (mService != null) { 150 mEcmTimeout = mService.getEmergencyCallbackModeTimeout(); 151 mInEmergencyCall = mService.getEmergencyCallbackModeCallState(); 152 } 153 154 // Unbind from remote service 155 unbindService(mConnection); 156 157 // Show dialog 158 mHandler.post(new Runnable() { 159 public void run() { 160 showEmergencyCallbackModeExitDialog(); 161 } 162 }); 163 } 164 }; 165 166 /** 167 * Shows Emergency Callback Mode dialog and starts countdown timer 168 */ showEmergencyCallbackModeExitDialog()169 private void showEmergencyCallbackModeExitDialog() { 170 171 if(mInEmergencyCall) { 172 mDialogType = EXIT_ECM_IN_EMERGENCY_CALL_DIALOG; 173 showDialog(EXIT_ECM_IN_EMERGENCY_CALL_DIALOG); 174 } else { 175 if (getIntent().getAction().equals( 176 TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS)) { 177 mDialogType = EXIT_ECM_BLOCK_OTHERS; 178 showDialog(EXIT_ECM_BLOCK_OTHERS); 179 } else if (getIntent().getAction().equals(ACTION_SHOW_ECM_EXIT_DIALOG)) { 180 mDialogType = EXIT_ECM_DIALOG; 181 showDialog(EXIT_ECM_DIALOG); 182 } 183 184 mTimer = new CountDownTimer(mEcmTimeout, 1000) { 185 @Override 186 public void onTick(long millisUntilFinished) { 187 CharSequence text = getDialogText(millisUntilFinished); 188 mAlertDialog.setMessage(text); 189 } 190 191 @Override 192 public void onFinish() { 193 //Do nothing 194 } 195 }.start(); 196 } 197 } 198 199 /** 200 * Creates dialog that enables users to exit Emergency Callback Mode 201 */ 202 @Override onCreateDialog(int id)203 protected Dialog onCreateDialog(int id) { 204 switch (id) { 205 case EXIT_ECM_BLOCK_OTHERS: 206 case EXIT_ECM_DIALOG: 207 CharSequence text = getDialogText(mEcmTimeout); 208 mAlertDialog = new AlertDialog.Builder(EmergencyCallbackModeExitDialog.this) 209 .setIcon(R.drawable.picture_emergency32x32) 210 .setTitle(R.string.phone_in_ecm_notification_title) 211 .setMessage(text) 212 .setPositiveButton(R.string.alert_dialog_yes, 213 new DialogInterface.OnClickListener() { 214 public void onClick(DialogInterface dialog,int whichButton) { 215 // User clicked Yes. Exit Emergency Callback Mode. 216 mPhone.exitEmergencyCallbackMode(); 217 218 // Show progress dialog 219 showDialog(EXIT_ECM_PROGRESS_DIALOG); 220 mTimer.cancel(); 221 } 222 }) 223 .setNegativeButton(R.string.alert_dialog_no, 224 new DialogInterface.OnClickListener() { 225 public void onClick(DialogInterface dialog, int whichButton) { 226 // User clicked No 227 setResult(RESULT_OK, (new Intent()).putExtra( 228 EXTRA_EXIT_ECM_RESULT, false)); 229 finish(); 230 } 231 }).create(); 232 mAlertDialog.setOnDismissListener(this); 233 return mAlertDialog; 234 235 case EXIT_ECM_IN_EMERGENCY_CALL_DIALOG: 236 mAlertDialog = new AlertDialog.Builder(EmergencyCallbackModeExitDialog.this) 237 .setIcon(R.drawable.picture_emergency32x32) 238 .setTitle(R.string.phone_in_ecm_notification_title) 239 .setMessage(R.string.alert_dialog_in_ecm_call) 240 .setNeutralButton(R.string.alert_dialog_dismiss, 241 new DialogInterface.OnClickListener() { 242 public void onClick(DialogInterface dialog, int whichButton) { 243 // User clicked Dismiss 244 setResult(RESULT_OK, (new Intent()).putExtra( 245 EXTRA_EXIT_ECM_RESULT, false)); 246 finish(); 247 } 248 }).create(); 249 mAlertDialog.setOnDismissListener(this); 250 return mAlertDialog; 251 252 case EXIT_ECM_PROGRESS_DIALOG: 253 mProgressDialog = new ProgressDialog(EmergencyCallbackModeExitDialog.this); 254 mProgressDialog.setMessage(getText(R.string.progress_dialog_exiting_ecm)); 255 mProgressDialog.setIndeterminate(true); 256 mProgressDialog.setCancelable(false); 257 return mProgressDialog; 258 259 default: 260 return null; 261 } 262 } 263 264 /** 265 * Returns dialog box text with updated timeout value 266 */ getDialogText(long millisUntilFinished)267 private CharSequence getDialogText(long millisUntilFinished) { 268 // Format time 269 int minutes = (int)(millisUntilFinished / 60000); 270 String time = String.format("%d:%02d", minutes, 271 (millisUntilFinished % 60000) / 1000); 272 273 switch (mDialogType) { 274 case EXIT_ECM_BLOCK_OTHERS: 275 return String.format(getResources().getQuantityText( 276 R.plurals.alert_dialog_not_avaialble_in_ecm, minutes).toString(), time); 277 case EXIT_ECM_DIALOG: 278 return String.format(getResources().getQuantityText(R.plurals.alert_dialog_exit_ecm, 279 minutes).toString(), time); 280 } 281 return null; 282 } 283 284 /** 285 * Closes activity when dialog is dismissed 286 */ onDismiss(DialogInterface dialog)287 public void onDismiss(DialogInterface dialog) { 288 EmergencyCallbackModeExitDialog.this.setResult(RESULT_OK, (new Intent()) 289 .putExtra(EXTRA_EXIT_ECM_RESULT, false)); 290 finish(); 291 } 292 293 /** 294 * Listens for Emergency Callback Mode state change intents 295 */ 296 private BroadcastReceiver mEcmExitReceiver = new BroadcastReceiver() { 297 @Override 298 public void onReceive(Context context, Intent intent) { 299 // Received exit Emergency Callback Mode notification close all dialogs 300 if (intent.getAction().equals( 301 TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) { 302 if (intent.getBooleanExtra("phoneinECMState", false) == false) { 303 if (mAlertDialog != null) 304 mAlertDialog.dismiss(); 305 if (mProgressDialog != null) 306 mProgressDialog.dismiss(); 307 EmergencyCallbackModeExitDialog.this.setResult(RESULT_OK, (new Intent()) 308 .putExtra(EXTRA_EXIT_ECM_RESULT, true)); 309 finish(); 310 } 311 } 312 } 313 }; 314 315 /** 316 * Class for interacting with the interface of the service 317 */ 318 private ServiceConnection mConnection = new ServiceConnection() { 319 public void onServiceConnected(ComponentName className, IBinder service) { 320 mService = ((EmergencyCallbackModeService.LocalBinder)service).getService(); 321 // Notify thread that connection is ready 322 synchronized (EmergencyCallbackModeExitDialog.this) { 323 EmergencyCallbackModeExitDialog.this.notify(); 324 } 325 } 326 327 public void onServiceDisconnected(ComponentName className) { 328 mService = null; 329 } 330 }; 331 332 /** 333 * Class for receiving framework timer reset notifications 334 */ 335 private Handler mTimerResetHandler = new Handler () { 336 public void handleMessage(Message msg) { 337 switch (msg.what) { 338 case ECM_TIMER_RESET: 339 if(!((Boolean)((AsyncResult) msg.obj).result).booleanValue()) { 340 EmergencyCallbackModeExitDialog.this.setResult(RESULT_OK, (new Intent()) 341 .putExtra(EXTRA_EXIT_ECM_RESULT, false)); 342 finish(); 343 } 344 break; 345 } 346 } 347 }; 348 } 349