blob: ea89387635532980fea49ca74b6fe876def77b4e [file] [log] [blame]
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001/*
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
17package com.android.phone;
18
19import android.app.Notification;
20import android.app.NotificationManager;
21import android.app.PendingIntent;
22import android.app.Service;
23import android.content.BroadcastReceiver;
24import android.content.Context;
25import android.content.Intent;
26import android.content.IntentFilter;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070027import android.os.AsyncResult;
28import android.os.Binder;
29import android.os.CountDownTimer;
30import android.os.Handler;
31import android.os.IBinder;
32import android.os.Message;
Frank Zhang34b1b642019-11-21 11:08:53 -060033import android.os.UserHandle;
Inseob Kim14bb3d02018-12-13 17:11:34 +090034import android.sysprop.TelephonyProperties;
Daniel Brightd24bee42020-01-09 22:11:15 -080035import android.telephony.TelephonyManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070036import android.util.Log;
37
Santos Cordon7d4ddf62013-07-10 11:58:08 -070038import com.android.internal.telephony.Phone;
39import com.android.internal.telephony.PhoneConstants;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070040import com.android.internal.telephony.TelephonyIntents;
fionaxu8b7620d2017-05-01 16:22:17 -070041import com.android.internal.telephony.util.NotificationChannelController;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070042
Brad Ebingercd3601b2017-05-09 15:27:27 -070043import java.text.SimpleDateFormat;
44
Santos Cordon7d4ddf62013-07-10 11:58:08 -070045/**
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 */
51public class EmergencyCallbackModeService extends Service {
52
53 // Default Emergency Callback Mode timeout value
Inseob Kim14bb3d02018-12-13 17:11:34 +090054 private static final long DEFAULT_ECM_EXIT_TIMER_VALUE = 300000L;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070055 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
76 public void onCreate() {
Sandeep Kuntade73a6a2014-10-15 18:45:56 +053077 Phone phoneInEcm = PhoneGlobals.getInstance().getPhoneInEcm();
Santos Cordon7d4ddf62013-07-10 11:58:08 -070078 // Check if it is CDMA phone
Sandeep Kuntade73a6a2014-10-15 18:45:56 +053079 if (phoneInEcm == null || ((phoneInEcm.getPhoneType() != PhoneConstants.PHONE_TYPE_CDMA)
80 && (phoneInEcm.getImsPhone() == null))) {
81 Log.e(LOG_TAG, "Error! Emergency Callback Mode not supported for " + phoneInEcm);
Santos Cordon7d4ddf62013-07-10 11:58:08 -070082 stopSelf();
Sandeep Kuntade73a6a2014-10-15 18:45:56 +053083 return;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070084 }
85
86 // Register receiver for intents
87 IntentFilter filter = new IntentFilter();
88 filter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
89 filter.addAction(TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS);
90 registerReceiver(mEcmReceiver, filter);
91
92 mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
93
94 // Register ECM timer reset notfication
Sandeep Kuntade73a6a2014-10-15 18:45:56 +053095 mPhone = phoneInEcm;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070096 mPhone.registerForEcmTimerReset(mHandler, ECM_TIMER_RESET, null);
97
98 startTimerNotification();
99 }
100
101 @Override
102 public void onDestroy() {
Sandeep Kunta55a6ae82015-12-14 17:49:02 +0530103 if (mPhone != null) {
104 // Unregister receiver
105 unregisterReceiver(mEcmReceiver);
106 // Unregister ECM timer reset notification
107 mPhone.unregisterForEcmTimerReset(mHandler);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700108
Sandeep Kunta55a6ae82015-12-14 17:49:02 +0530109 // Cancel the notification and timer
Frank Zhang34b1b642019-11-21 11:08:53 -0600110 mNotificationManager.cancelAsUser(null, R.string.phone_in_ecm_notification_title,
111 UserHandle.ALL);
Sandeep Kunta55a6ae82015-12-14 17:49:02 +0530112 mTimer.cancel();
113 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700114 }
115
116 /**
117 * Listens for Emergency Callback Mode intents
118 */
119 private BroadcastReceiver mEcmReceiver = new BroadcastReceiver() {
120 @Override
121 public void onReceive(Context context, Intent intent) {
122 // Stop the service when phone exits Emergency Callback Mode
123 if (intent.getAction().equals(
124 TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) {
Daniel Brightd24bee42020-01-09 22:11:15 -0800125 if (!intent.getBooleanExtra(TelephonyManager.EXTRA_PHONE_IN_ECM_STATE, false)) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700126 stopSelf();
127 }
128 }
129 // Show dialog box
130 else if (intent.getAction().equals(
131 TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS)) {
132 context.startActivity(
133 new Intent(TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS)
134 .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
135 }
136 }
137 };
138
139 /**
140 * Start timer notification for Emergency Callback Mode
141 */
142 private void startTimerNotification() {
143 // Get Emergency Callback Mode timeout value
Inseob Kim14bb3d02018-12-13 17:11:34 +0900144 long ecmTimeout = TelephonyProperties.ecm_exit_timer().orElse(DEFAULT_ECM_EXIT_TIMER_VALUE);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700145
146 // Show the notification
147 showNotification(ecmTimeout);
148
149 // Start countdown timer for the notification updates
Yorke Lee34a72cb2014-10-12 13:17:04 -0700150 if (mTimer != null) {
151 mTimer.cancel();
152 } else {
153 mTimer = new CountDownTimer(ecmTimeout, 1000) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700154
Yorke Lee34a72cb2014-10-12 13:17:04 -0700155 @Override
156 public void onTick(long millisUntilFinished) {
157 mTimeLeft = millisUntilFinished;
Yorke Lee34a72cb2014-10-12 13:17:04 -0700158 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700159
Yorke Lee34a72cb2014-10-12 13:17:04 -0700160 @Override
161 public void onFinish() {
162 //Do nothing
163 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700164
Yorke Lee34a72cb2014-10-12 13:17:04 -0700165 };
166 }
167 mTimer.start();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700168 }
169
170 /**
171 * Shows notification for Emergency Callback Mode
172 */
173 private void showNotification(long millisUntilFinished) {
Amit Mahajan6a2f8752016-07-25 11:38:10 -0700174 Phone imsPhone = mPhone.getImsPhone();
175 boolean isInEcm = mPhone.isInEcm() || (imsPhone != null && imsPhone.isInEcm());
Yorke Lee34a72cb2014-10-12 13:17:04 -0700176 if (!isInEcm) {
177 Log.i(LOG_TAG, "Asked to show notification but not in ECM mode");
178 if (mTimer != null) {
179 mTimer.cancel();
180 }
181 return;
182 }
fionaxu8b7620d2017-05-01 16:22:17 -0700183 final Notification.Builder builder = new Notification.Builder(getApplicationContext());
Tyler Gunn625eb0b2014-08-27 20:37:32 -0700184 builder.setOngoing(true);
185 builder.setPriority(Notification.PRIORITY_HIGH);
186 builder.setSmallIcon(R.drawable.ic_emergency_callback_mode);
187 builder.setTicker(getText(R.string.phone_entered_ecm_text));
188 builder.setContentTitle(getText(R.string.phone_in_ecm_notification_title));
189 builder.setColor(getResources().getColor(R.color.dialer_theme_color));
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700190
191 // PendingIntent to launch Emergency Callback Mode Exit activity if the user selects
192 // this notification
193 PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
194 new Intent(EmergencyCallbackModeExitDialog.ACTION_SHOW_ECM_EXIT_DIALOG), 0);
Tyler Gunn625eb0b2014-08-27 20:37:32 -0700195 builder.setContentIntent(contentIntent);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700196
197 // Format notification string
198 String text = null;
199 if(mInEmergencyCall) {
200 text = getText(R.string.phone_in_ecm_call_notification_text).toString();
201 } else {
Brad Ebingercd3601b2017-05-09 15:27:27 -0700202 // Calculate the time in ms when the notification will be finished.
203 long finishedCountMs = millisUntilFinished + System.currentTimeMillis();
204 builder.setShowWhen(true);
205 builder.setChronometerCountDown(true);
206 builder.setUsesChronometer(true);
207 builder.setWhen(finishedCountMs);
208
209 String completeTime = SimpleDateFormat.getTimeInstance(SimpleDateFormat.SHORT).format(
210 finishedCountMs);
211 text = getResources().getString(R.string.phone_in_ecm_notification_complete_time,
212 completeTime);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700213 }
Tyler Gunn625eb0b2014-08-27 20:37:32 -0700214 builder.setContentText(text);
fionaxu8b7620d2017-05-01 16:22:17 -0700215 builder.setChannelId(NotificationChannelController.CHANNEL_ID_ALERT);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700216
217 // Show notification
Frank Zhang34b1b642019-11-21 11:08:53 -0600218 mNotificationManager.notifyAsUser(null, R.string.phone_in_ecm_notification_title,
219 builder.build(), UserHandle.ALL);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700220 }
221
222 /**
223 * Handle ECM_TIMER_RESET notification
224 */
225 private void resetEcmTimer(AsyncResult r) {
226 boolean isTimerCanceled = ((Boolean)r.result).booleanValue();
227
228 if (isTimerCanceled) {
229 mInEmergencyCall = true;
230 mTimer.cancel();
231 showNotification(0);
232 } else {
233 mInEmergencyCall = false;
234 startTimerNotification();
235 }
236 }
237
238 @Override
239 public IBinder onBind(Intent intent) {
240 return mBinder;
241 }
242
243 // This is the object that receives interactions from clients.
244 private final IBinder mBinder = new LocalBinder();
245
246 /**
247 * Class for clients to access
248 */
249 public class LocalBinder extends Binder {
250 EmergencyCallbackModeService getService() {
251 return EmergencyCallbackModeService.this;
252 }
253 }
254
255 /**
256 * Returns Emergency Callback Mode timeout value
257 */
258 public long getEmergencyCallbackModeTimeout() {
259 return mTimeLeft;
260 }
261
262 /**
263 * Returns Emergency Callback Mode call state
264 */
265 public boolean getEmergencyCallbackModeCallState() {
266 return mInEmergencyCall;
267 }
268}