| Santos Cordon | 7d4ddf6 | 2013-07-10 11:58:08 -0700 | [diff] [blame] | 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; | 
| Santos Cordon | 7d4ddf6 | 2013-07-10 11:58:08 -0700 | [diff] [blame] | 27 | import android.os.AsyncResult; | 
|  | 28 | import android.os.Binder; | 
|  | 29 | import android.os.CountDownTimer; | 
|  | 30 | import android.os.Handler; | 
|  | 31 | import android.os.IBinder; | 
|  | 32 | import android.os.Message; | 
|  | 33 | import android.os.SystemProperties; | 
|  | 34 | import android.util.Log; | 
|  | 35 |  | 
| Santos Cordon | 7d4ddf6 | 2013-07-10 11:58:08 -0700 | [diff] [blame] | 36 | import com.android.internal.telephony.Phone; | 
|  | 37 | import com.android.internal.telephony.PhoneConstants; | 
| Santos Cordon | 7d4ddf6 | 2013-07-10 11:58:08 -0700 | [diff] [blame] | 38 | import com.android.internal.telephony.TelephonyIntents; | 
|  | 39 | import com.android.internal.telephony.TelephonyProperties; | 
| fionaxu | 8b7620d | 2017-05-01 16:22:17 -0700 | [diff] [blame] | 40 | import com.android.internal.telephony.util.NotificationChannelController; | 
| Santos Cordon | 7d4ddf6 | 2013-07-10 11:58:08 -0700 | [diff] [blame] | 41 |  | 
|  | 42 | /** | 
|  | 43 | * Application service that inserts/removes Emergency Callback Mode notification and | 
|  | 44 | * updates Emergency Callback Mode countdown clock in the notification | 
|  | 45 | * | 
|  | 46 | * @see EmergencyCallbackModeExitDialog | 
|  | 47 | */ | 
|  | 48 | public class EmergencyCallbackModeService extends Service { | 
|  | 49 |  | 
|  | 50 | // Default Emergency Callback Mode timeout value | 
|  | 51 | private static final int DEFAULT_ECM_EXIT_TIMER_VALUE = 300000; | 
|  | 52 | private static final String LOG_TAG = "EmergencyCallbackModeService"; | 
|  | 53 |  | 
|  | 54 | private NotificationManager mNotificationManager = null; | 
|  | 55 | private CountDownTimer mTimer = null; | 
|  | 56 | private long mTimeLeft = 0; | 
|  | 57 | private Phone mPhone = null; | 
|  | 58 | private boolean mInEmergencyCall = false; | 
|  | 59 |  | 
|  | 60 | private static final int ECM_TIMER_RESET = 1; | 
|  | 61 |  | 
|  | 62 | private Handler mHandler = new Handler () { | 
|  | 63 | public void handleMessage(Message msg) { | 
|  | 64 | switch (msg.what) { | 
|  | 65 | case ECM_TIMER_RESET: | 
|  | 66 | resetEcmTimer((AsyncResult) msg.obj); | 
|  | 67 | break; | 
|  | 68 | } | 
|  | 69 | } | 
|  | 70 | }; | 
|  | 71 |  | 
|  | 72 | @Override | 
|  | 73 | public void onCreate() { | 
| Sandeep Kunta | de73a6a | 2014-10-15 18:45:56 +0530 | [diff] [blame] | 74 | Phone phoneInEcm = PhoneGlobals.getInstance().getPhoneInEcm(); | 
| Santos Cordon | 7d4ddf6 | 2013-07-10 11:58:08 -0700 | [diff] [blame] | 75 | // Check if it is CDMA phone | 
| Sandeep Kunta | de73a6a | 2014-10-15 18:45:56 +0530 | [diff] [blame] | 76 | if (phoneInEcm == null || ((phoneInEcm.getPhoneType() != PhoneConstants.PHONE_TYPE_CDMA) | 
|  | 77 | && (phoneInEcm.getImsPhone() == null))) { | 
|  | 78 | Log.e(LOG_TAG, "Error! Emergency Callback Mode not supported for " + phoneInEcm); | 
| Santos Cordon | 7d4ddf6 | 2013-07-10 11:58:08 -0700 | [diff] [blame] | 79 | stopSelf(); | 
| Sandeep Kunta | de73a6a | 2014-10-15 18:45:56 +0530 | [diff] [blame] | 80 | return; | 
| Santos Cordon | 7d4ddf6 | 2013-07-10 11:58:08 -0700 | [diff] [blame] | 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 | 
| Sandeep Kunta | de73a6a | 2014-10-15 18:45:56 +0530 | [diff] [blame] | 92 | mPhone = phoneInEcm; | 
| Santos Cordon | 7d4ddf6 | 2013-07-10 11:58:08 -0700 | [diff] [blame] | 93 | mPhone.registerForEcmTimerReset(mHandler, ECM_TIMER_RESET, null); | 
|  | 94 |  | 
|  | 95 | startTimerNotification(); | 
|  | 96 | } | 
|  | 97 |  | 
|  | 98 | @Override | 
|  | 99 | public void onDestroy() { | 
| Sandeep Kunta | 55a6ae8 | 2015-12-14 17:49:02 +0530 | [diff] [blame] | 100 | if (mPhone != null) { | 
|  | 101 | // Unregister receiver | 
|  | 102 | unregisterReceiver(mEcmReceiver); | 
|  | 103 | // Unregister ECM timer reset notification | 
|  | 104 | mPhone.unregisterForEcmTimerReset(mHandler); | 
| Santos Cordon | 7d4ddf6 | 2013-07-10 11:58:08 -0700 | [diff] [blame] | 105 |  | 
| Sandeep Kunta | 55a6ae8 | 2015-12-14 17:49:02 +0530 | [diff] [blame] | 106 | // Cancel the notification and timer | 
|  | 107 | mNotificationManager.cancel(R.string.phone_in_ecm_notification_title); | 
|  | 108 | mTimer.cancel(); | 
|  | 109 | } | 
| Santos Cordon | 7d4ddf6 | 2013-07-10 11:58:08 -0700 | [diff] [blame] | 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 | */ | 
|  | 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 | 
| Yorke Lee | 34a72cb | 2014-10-12 13:17:04 -0700 | [diff] [blame] | 147 | if (mTimer != null) { | 
|  | 148 | mTimer.cancel(); | 
|  | 149 | } else { | 
|  | 150 | mTimer = new CountDownTimer(ecmTimeout, 1000) { | 
| Santos Cordon | 7d4ddf6 | 2013-07-10 11:58:08 -0700 | [diff] [blame] | 151 |  | 
| Yorke Lee | 34a72cb | 2014-10-12 13:17:04 -0700 | [diff] [blame] | 152 | @Override | 
|  | 153 | public void onTick(long millisUntilFinished) { | 
|  | 154 | mTimeLeft = millisUntilFinished; | 
|  | 155 | EmergencyCallbackModeService.this.showNotification(millisUntilFinished); | 
|  | 156 | } | 
| Santos Cordon | 7d4ddf6 | 2013-07-10 11:58:08 -0700 | [diff] [blame] | 157 |  | 
| Yorke Lee | 34a72cb | 2014-10-12 13:17:04 -0700 | [diff] [blame] | 158 | @Override | 
|  | 159 | public void onFinish() { | 
|  | 160 | //Do nothing | 
|  | 161 | } | 
| Santos Cordon | 7d4ddf6 | 2013-07-10 11:58:08 -0700 | [diff] [blame] | 162 |  | 
| Yorke Lee | 34a72cb | 2014-10-12 13:17:04 -0700 | [diff] [blame] | 163 | }; | 
|  | 164 | } | 
|  | 165 | mTimer.start(); | 
| Santos Cordon | 7d4ddf6 | 2013-07-10 11:58:08 -0700 | [diff] [blame] | 166 | } | 
|  | 167 |  | 
|  | 168 | /** | 
|  | 169 | * Shows notification for Emergency Callback Mode | 
|  | 170 | */ | 
|  | 171 | private void showNotification(long millisUntilFinished) { | 
| Amit Mahajan | 6a2f875 | 2016-07-25 11:38:10 -0700 | [diff] [blame] | 172 | Phone imsPhone = mPhone.getImsPhone(); | 
|  | 173 | boolean isInEcm = mPhone.isInEcm() || (imsPhone != null && imsPhone.isInEcm()); | 
| Yorke Lee | 34a72cb | 2014-10-12 13:17:04 -0700 | [diff] [blame] | 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 | } | 
| fionaxu | 8b7620d | 2017-05-01 16:22:17 -0700 | [diff] [blame] | 181 | final Notification.Builder builder = new Notification.Builder(getApplicationContext()); | 
| Tyler Gunn | 625eb0b | 2014-08-27 20:37:32 -0700 | [diff] [blame] | 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)); | 
| Santos Cordon | 7d4ddf6 | 2013-07-10 11:58:08 -0700 | [diff] [blame] | 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); | 
| Tyler Gunn | 625eb0b | 2014-08-27 20:37:32 -0700 | [diff] [blame] | 193 | builder.setContentIntent(contentIntent); | 
| Santos Cordon | 7d4ddf6 | 2013-07-10 11:58:08 -0700 | [diff] [blame] | 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 | } | 
| Tyler Gunn | 625eb0b | 2014-08-27 20:37:32 -0700 | [diff] [blame] | 205 | builder.setContentText(text); | 
| fionaxu | 8b7620d | 2017-05-01 16:22:17 -0700 | [diff] [blame] | 206 | builder.setChannelId(NotificationChannelController.CHANNEL_ID_ALERT); | 
| Santos Cordon | 7d4ddf6 | 2013-07-10 11:58:08 -0700 | [diff] [blame] | 207 |  | 
|  | 208 | // Show notification | 
| Tyler Gunn | 625eb0b | 2014-08-27 20:37:32 -0700 | [diff] [blame] | 209 | mNotificationManager.notify(R.string.phone_in_ecm_notification_title, builder.build()); | 
| Santos Cordon | 7d4ddf6 | 2013-07-10 11:58:08 -0700 | [diff] [blame] | 210 | } | 
|  | 211 |  | 
|  | 212 | /** | 
|  | 213 | * Handle ECM_TIMER_RESET notification | 
|  | 214 | */ | 
|  | 215 | private void resetEcmTimer(AsyncResult r) { | 
|  | 216 | boolean isTimerCanceled = ((Boolean)r.result).booleanValue(); | 
|  | 217 |  | 
|  | 218 | if (isTimerCanceled) { | 
|  | 219 | mInEmergencyCall = true; | 
|  | 220 | mTimer.cancel(); | 
|  | 221 | showNotification(0); | 
|  | 222 | } else { | 
|  | 223 | mInEmergencyCall = false; | 
|  | 224 | startTimerNotification(); | 
|  | 225 | } | 
|  | 226 | } | 
|  | 227 |  | 
|  | 228 | @Override | 
|  | 229 | public IBinder onBind(Intent intent) { | 
|  | 230 | return mBinder; | 
|  | 231 | } | 
|  | 232 |  | 
|  | 233 | // This is the object that receives interactions from clients. | 
|  | 234 | private final IBinder mBinder = new LocalBinder(); | 
|  | 235 |  | 
|  | 236 | /** | 
|  | 237 | * Class for clients to access | 
|  | 238 | */ | 
|  | 239 | public class LocalBinder extends Binder { | 
|  | 240 | EmergencyCallbackModeService getService() { | 
|  | 241 | return EmergencyCallbackModeService.this; | 
|  | 242 | } | 
|  | 243 | } | 
|  | 244 |  | 
|  | 245 | /** | 
|  | 246 | * Returns Emergency Callback Mode timeout value | 
|  | 247 | */ | 
|  | 248 | public long getEmergencyCallbackModeTimeout() { | 
|  | 249 | return mTimeLeft; | 
|  | 250 | } | 
|  | 251 |  | 
|  | 252 | /** | 
|  | 253 | * Returns Emergency Callback Mode call state | 
|  | 254 | */ | 
|  | 255 | public boolean getEmergencyCallbackModeCallState() { | 
|  | 256 | return mInEmergencyCall; | 
|  | 257 | } | 
|  | 258 | } |