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         mPhone = PhoneGlobals.getInstance().getPhoneInEcm();
     82         // Check if phone is in Emergency Callback Mode. If not, exit.
     83         final boolean isInEcm = mPhone.isInEcm();
     84         Log.i(TAG, "ECMModeExitDialog launched - isInEcm: " + isInEcm + " phone:" + mPhone);
     85         if (mPhone == null || !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.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();
    110         try {
    111             unregisterReceiver(mEcmExitReceiver);
    112         } catch (IllegalArgumentException e) {
    113             // Receiver was never registered - silently ignore.
    114         }
    115         // Unregister ECM timer reset notification
    116         if (mPhone != null) {
    117             mPhone.unregisterForEcmTimerReset(mHandler);
    118         }
    119     }
    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();
    161                 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                 }
    169             }
    170 
    171             // 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() {
    184         if (!this.isResumed()) {
    185             Log.w(TAG, "Tried to show dialog, but activity was already finished");
    186             return;
    187         }
    188         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)
    226                     .setIcon(R.drawable.ic_emergency_callback_mode)
    227                     .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();
    249             mAlertDialog.setOnDismissListener(this);
    250             return mAlertDialog;
    251 
    252         case EXIT_ECM_IN_EMERGENCY_CALL_DIALOG:
    253             mAlertDialog = new AlertDialog.Builder(EmergencyCallbackModeExitDialog.this)
    254                     .setIcon(R.drawable.ic_emergency_callback_mode)
    255                     .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();
    266             mAlertDialog.setOnDismissListener(this);
    267             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     /**
    302      * Closes activity when dialog is dismissed
    303      */
    304     @Override
    305     public void onDismiss(DialogInterface dialog) {
    306         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 }
    367