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