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