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     /** 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 = PhoneApp.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