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