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