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.Notification; 20 import android.app.NotificationManager; 21 import android.app.PendingIntent; 22 import android.app.Service; 23 import android.content.BroadcastReceiver; 24 import android.content.Context; 25 import android.content.Intent; 26 import android.content.IntentFilter; 27 import android.content.res.Resources; 28 import android.os.AsyncResult; 29 import android.os.Binder; 30 import android.os.CountDownTimer; 31 import android.os.Handler; 32 import android.os.IBinder; 33 import android.os.Message; 34 import android.os.SystemProperties; 35 import android.util.Log; 36 37 import com.android.internal.telephony.cdma.CDMAPhone; 38 import com.android.internal.telephony.Phone; 39 import com.android.internal.telephony.PhoneConstants; 40 import com.android.internal.telephony.PhoneFactory; 41 import com.android.internal.telephony.TelephonyIntents; 42 import com.android.internal.telephony.TelephonyProperties; 43 44 /** 45 * Application service that inserts/removes Emergency Callback Mode notification and 46 * updates Emergency Callback Mode countdown clock in the notification 47 * 48 * @see EmergencyCallbackModeExitDialog 49 */ 50 public class EmergencyCallbackModeService extends Service { 51 52 // Default Emergency Callback Mode timeout value 53 private static final int DEFAULT_ECM_EXIT_TIMER_VALUE = 300000; 54 private static final String LOG_TAG = "EmergencyCallbackModeService"; 55 56 private NotificationManager mNotificationManager = null; 57 private CountDownTimer mTimer = null; 58 private long mTimeLeft = 0; 59 private Phone mPhone = null; 60 private boolean mInEmergencyCall = false; 61 62 private static final int ECM_TIMER_RESET = 1; 63 64 private Handler mHandler = new Handler () { 65 public void handleMessage(Message msg) { 66 switch (msg.what) { 67 case ECM_TIMER_RESET: 68 resetEcmTimer((AsyncResult) msg.obj); 69 break; 70 } 71 } 72 }; 73 74 @Override 75 public void onCreate() { 76 // Check if it is CDMA phone 77 if (PhoneFactory.getDefaultPhone().getPhoneType() != PhoneConstants.PHONE_TYPE_CDMA) { 78 Log.e(LOG_TAG, "Error! Emergency Callback Mode not supported for " + 79 PhoneFactory.getDefaultPhone().getPhoneName() + " phones"); 80 stopSelf(); 81 } 82 83 // Register receiver for intents 84 IntentFilter filter = new IntentFilter(); 85 filter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED); 86 filter.addAction(TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS); 87 registerReceiver(mEcmReceiver, filter); 88 89 mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); 90 91 // Register ECM timer reset notfication 92 mPhone = PhoneFactory.getDefaultPhone(); 93 mPhone.registerForEcmTimerReset(mHandler, ECM_TIMER_RESET, null); 94 95 startTimerNotification(); 96 } 97 98 @Override 99 public void onDestroy() { 100 // Unregister receiver 101 unregisterReceiver(mEcmReceiver); 102 // Unregister ECM timer reset notification 103 mPhone.unregisterForEcmTimerReset(mHandler); 104 105 // Cancel the notification and timer 106 mNotificationManager.cancel(R.string.phone_in_ecm_notification_title); 107 mTimer.cancel(); 108 } 109 110 /** 111 * Listens for Emergency Callback Mode intents 112 */ 113 private BroadcastReceiver mEcmReceiver = new BroadcastReceiver() { 114 @Override 115 public void onReceive(Context context, Intent intent) { 116 // Stop the service when phone exits Emergency Callback Mode 117 if (intent.getAction().equals( 118 TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) { 119 if (intent.getBooleanExtra("phoneinECMState", false) == false) { 120 stopSelf(); 121 } 122 } 123 // Show dialog box 124 else if (intent.getAction().equals( 125 TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS)) { 126 context.startActivity( 127 new Intent(TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS) 128 .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); 129 } 130 } 131 }; 132 133 /** 134 * Start timer notification for Emergency Callback Mode 135 */ 136 private void startTimerNotification() { 137 // Get Emergency Callback Mode timeout value 138 long ecmTimeout = SystemProperties.getLong( 139 TelephonyProperties.PROPERTY_ECM_EXIT_TIMER, DEFAULT_ECM_EXIT_TIMER_VALUE); 140 141 // Show the notification 142 showNotification(ecmTimeout); 143 144 // Start countdown timer for the notification updates 145 mTimer = new CountDownTimer(ecmTimeout, 1000) { 146 147 @Override 148 public void onTick(long millisUntilFinished) { 149 mTimeLeft = millisUntilFinished; 150 EmergencyCallbackModeService.this.showNotification(millisUntilFinished); 151 } 152 153 @Override 154 public void onFinish() { 155 //Do nothing 156 } 157 158 }.start(); 159 } 160 161 /** 162 * Shows notification for Emergency Callback Mode 163 */ 164 private void showNotification(long millisUntilFinished) { 165 166 // Set the icon and text 167 Notification notification = new Notification( 168 R.drawable.picture_emergency25x25, 169 getText(R.string.phone_entered_ecm_text), 0); 170 171 // PendingIntent to launch Emergency Callback Mode Exit activity if the user selects 172 // this notification 173 PendingIntent contentIntent = PendingIntent.getActivity(this, 0, 174 new Intent(EmergencyCallbackModeExitDialog.ACTION_SHOW_ECM_EXIT_DIALOG), 0); 175 176 // Format notification string 177 String text = null; 178 if(mInEmergencyCall) { 179 text = getText(R.string.phone_in_ecm_call_notification_text).toString(); 180 } else { 181 int minutes = (int)(millisUntilFinished / 60000); 182 String time = String.format("%d:%02d", minutes, (millisUntilFinished % 60000) / 1000); 183 text = String.format(getResources().getQuantityText( 184 R.plurals.phone_in_ecm_notification_time, minutes).toString(), time); 185 } 186 // Set the info in the notification 187 notification.setLatestEventInfo(this, getText(R.string.phone_in_ecm_notification_title), 188 text, contentIntent); 189 190 notification.flags = Notification.FLAG_ONGOING_EVENT; 191 192 // Show notification 193 mNotificationManager.notify(R.string.phone_in_ecm_notification_title, notification); 194 } 195 196 /** 197 * Handle ECM_TIMER_RESET notification 198 */ 199 private void resetEcmTimer(AsyncResult r) { 200 boolean isTimerCanceled = ((Boolean)r.result).booleanValue(); 201 202 if (isTimerCanceled) { 203 mInEmergencyCall = true; 204 mTimer.cancel(); 205 showNotification(0); 206 } else { 207 mInEmergencyCall = false; 208 startTimerNotification(); 209 } 210 } 211 212 @Override 213 public IBinder onBind(Intent intent) { 214 return mBinder; 215 } 216 217 // This is the object that receives interactions from clients. 218 private final IBinder mBinder = new LocalBinder(); 219 220 /** 221 * Class for clients to access 222 */ 223 public class LocalBinder extends Binder { 224 EmergencyCallbackModeService getService() { 225 return EmergencyCallbackModeService.this; 226 } 227 } 228 229 /** 230 * Returns Emergency Callback Mode timeout value 231 */ 232 public long getEmergencyCallbackModeTimeout() { 233 return mTimeLeft; 234 } 235 236 /** 237 * Returns Emergency Callback Mode call state 238 */ 239 public boolean getEmergencyCallbackModeCallState() { 240 return mInEmergencyCall; 241 } 242 } 243