• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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.internal.telephony;
18 
19 import android.app.Notification;
20 import android.app.NotificationManager;
21 import android.app.PendingIntent;
22 import android.content.BroadcastReceiver;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.content.IntentFilter;
26 import android.content.res.Resources;
27 import android.os.Handler;
28 import android.os.HandlerExecutor;
29 import android.os.Message;
30 import android.os.PersistableBundle;
31 import android.provider.Settings;
32 import android.telephony.CarrierConfigManager;
33 import android.telephony.RadioAccessFamily;
34 import android.telephony.ServiceState;
35 import android.telephony.SubscriptionManager;
36 import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
37 import android.telephony.TelephonyCallback;
38 import android.telephony.TelephonyManager;
39 import android.telephony.TelephonyManager.NetworkTypeBitMask;
40 
41 import com.android.internal.annotations.VisibleForTesting;
42 import com.android.internal.telephony.util.ArrayUtils;
43 import com.android.internal.telephony.util.NotificationChannelController;
44 import com.android.telephony.Rlog;
45 
46 import java.util.HashMap;
47 import java.util.Map;
48 
49 /**
50  * This contains Carrier specific logic based on the states/events
51  * managed in ServiceStateTracker.
52  * {@hide}
53  */
54 public class CarrierServiceStateTracker extends Handler {
55     private static final String LOG_TAG = "CSST";
56     protected static final int CARRIER_EVENT_BASE = 100;
57     protected static final int CARRIER_EVENT_VOICE_REGISTRATION = CARRIER_EVENT_BASE + 1;
58     protected static final int CARRIER_EVENT_VOICE_DEREGISTRATION = CARRIER_EVENT_BASE + 2;
59     protected static final int CARRIER_EVENT_DATA_REGISTRATION = CARRIER_EVENT_BASE + 3;
60     protected static final int CARRIER_EVENT_DATA_DEREGISTRATION = CARRIER_EVENT_BASE + 4;
61     protected static final int CARRIER_EVENT_IMS_CAPABILITIES_CHANGED = CARRIER_EVENT_BASE + 5;
62 
63     private static final int UNINITIALIZED_DELAY_VALUE = -1;
64     private Phone mPhone;
65     private ServiceStateTracker mSST;
66     private final Map<Integer, NotificationType> mNotificationTypeMap = new HashMap<>();
67     private int mPreviousSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
68     public static final int NOTIFICATION_PREF_NETWORK = 1000;
69     public static final int NOTIFICATION_EMERGENCY_NETWORK = 1001;
70 
71     @VisibleForTesting
72     public static final String EMERGENCY_NOTIFICATION_TAG = "EmergencyNetworkNotification";
73 
74     @VisibleForTesting
75     public static final String PREF_NETWORK_NOTIFICATION_TAG = "PrefNetworkNotification";
76 
77     private long mAllowedNetworkType = -1;
78     private AllowedNetworkTypesListener mAllowedNetworkTypesListener;
79     private TelephonyManager mTelephonyManager;
80 
81     /**
82      * The listener for allowed network types changed
83      */
84     @VisibleForTesting
85     public class AllowedNetworkTypesListener extends TelephonyCallback
86             implements TelephonyCallback.AllowedNetworkTypesListener {
87         @Override
onAllowedNetworkTypesChanged(int reason, long newAllowedNetworkType)88         public void onAllowedNetworkTypesChanged(int reason, long newAllowedNetworkType) {
89             if (reason != TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER) {
90                 return;
91             }
92 
93             if (mAllowedNetworkType != newAllowedNetworkType) {
94                 mAllowedNetworkType = newAllowedNetworkType;
95                 handleAllowedNetworkTypeChanged();
96             }
97         }
98     }
99 
CarrierServiceStateTracker(Phone phone, ServiceStateTracker sst)100     public CarrierServiceStateTracker(Phone phone, ServiceStateTracker sst) {
101         this.mPhone = phone;
102         this.mSST = sst;
103         mTelephonyManager = mPhone.getContext().getSystemService(
104                 TelephonyManager.class).createForSubscriptionId(mPhone.getSubId());
105         phone.getContext().registerReceiver(mBroadcastReceiver, new IntentFilter(
106                 CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED));
107         // Listen for subscriber changes
108         SubscriptionManager.from(mPhone.getContext()).addOnSubscriptionsChangedListener(
109                 new OnSubscriptionsChangedListener(this.getLooper()) {
110                     @Override
111                     public void onSubscriptionsChanged() {
112                         int subId = mPhone.getSubId();
113                         if (mPreviousSubId != subId) {
114                             mPreviousSubId = subId;
115                             mTelephonyManager = mTelephonyManager.createForSubscriptionId(
116                                     mPhone.getSubId());
117                             registerAllowedNetworkTypesListener();
118                         }
119                     }
120                 });
121 
122         registerNotificationTypes();
123         mAllowedNetworkType = RadioAccessFamily.getNetworkTypeFromRaf(
124                 (int) mPhone.getAllowedNetworkTypes(
125                         TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER));
126         mAllowedNetworkTypesListener = new AllowedNetworkTypesListener();
127         registerAllowedNetworkTypesListener();
128     }
129 
130     /**
131      * Return preferred network mode listener
132      */
133     @VisibleForTesting
getAllowedNetworkTypesChangedListener()134     public AllowedNetworkTypesListener getAllowedNetworkTypesChangedListener() {
135         return mAllowedNetworkTypesListener;
136     }
137 
registerAllowedNetworkTypesListener()138     private void registerAllowedNetworkTypesListener() {
139         int subId = mPhone.getSubId();
140         unregisterAllowedNetworkTypesListener();
141         if (SubscriptionManager.isValidSubscriptionId(subId)) {
142             if (mTelephonyManager != null) {
143                 mTelephonyManager.registerTelephonyCallback(new HandlerExecutor(this),
144                         mAllowedNetworkTypesListener);
145             }
146         }
147     }
148 
unregisterAllowedNetworkTypesListener()149     private void unregisterAllowedNetworkTypesListener() {
150         mTelephonyManager.unregisterTelephonyCallback(mAllowedNetworkTypesListener);
151     }
152 
153     /**
154      * Returns mNotificationTypeMap
155      */
156     @VisibleForTesting
getNotificationTypeMap()157     public Map<Integer, NotificationType> getNotificationTypeMap() {
158         return mNotificationTypeMap;
159     }
160 
registerNotificationTypes()161     private void registerNotificationTypes() {
162         mNotificationTypeMap.put(NOTIFICATION_PREF_NETWORK,
163                 new PrefNetworkNotification(NOTIFICATION_PREF_NETWORK));
164         mNotificationTypeMap.put(NOTIFICATION_EMERGENCY_NETWORK,
165                 new EmergencyNetworkNotification(NOTIFICATION_EMERGENCY_NETWORK));
166     }
167 
168     @Override
handleMessage(Message msg)169     public void handleMessage(Message msg) {
170         switch (msg.what) {
171             case CARRIER_EVENT_VOICE_REGISTRATION:
172             case CARRIER_EVENT_DATA_REGISTRATION:
173             case CARRIER_EVENT_VOICE_DEREGISTRATION:
174             case CARRIER_EVENT_DATA_DEREGISTRATION:
175                 handleConfigChanges();
176                 break;
177             case CARRIER_EVENT_IMS_CAPABILITIES_CHANGED:
178                 handleImsCapabilitiesChanged();
179                 break;
180             case NOTIFICATION_EMERGENCY_NETWORK:
181             case NOTIFICATION_PREF_NETWORK:
182                 Rlog.d(LOG_TAG, "sending notification after delay: " + msg.what);
183                 NotificationType notificationType = mNotificationTypeMap.get(msg.what);
184                 if (notificationType != null) {
185                     sendNotification(notificationType);
186                 }
187                 break;
188         }
189     }
190 
isPhoneStillRegistered()191     private boolean isPhoneStillRegistered() {
192         if (mSST.mSS == null) {
193             return true; //something has gone wrong, return true and not show the notification.
194         }
195         return (mSST.mSS.getState() == ServiceState.STATE_IN_SERVICE
196                 || mSST.mSS.getDataRegistrationState() == ServiceState.STATE_IN_SERVICE);
197     }
198 
isPhoneRegisteredForWifiCalling()199     private boolean isPhoneRegisteredForWifiCalling() {
200         Rlog.d(LOG_TAG, "isPhoneRegisteredForWifiCalling: " + mPhone.isWifiCallingEnabled());
201         return mPhone.isWifiCallingEnabled();
202     }
203 
204     /**
205      * Returns true if the radio is off or in Airplane Mode else returns false.
206      */
207     @VisibleForTesting
isRadioOffOrAirplaneMode()208     public boolean isRadioOffOrAirplaneMode() {
209         Context context = mPhone.getContext();
210         int airplaneMode = -1;
211         try {
212             airplaneMode = Settings.Global.getInt(context.getContentResolver(),
213                     Settings.Global.AIRPLANE_MODE_ON, 0);
214         } catch (Exception e) {
215             Rlog.e(LOG_TAG, "Unable to get AIRPLACE_MODE_ON.");
216             return true;
217         }
218         return (!mSST.isRadioOn() || (airplaneMode != 0));
219     }
220 
221     /**
222      * Returns true if the preferred network is set to 'Global'.
223      */
isGlobalMode()224     private boolean isGlobalMode() {
225         int preferredNetworkSetting = -1;
226         try {
227             preferredNetworkSetting = PhoneFactory.calculatePreferredNetworkType(
228                     mPhone.getPhoneId());
229         } catch (Exception e) {
230             Rlog.e(LOG_TAG, "Unable to get PREFERRED_NETWORK_MODE.");
231             return true;
232         }
233 
234         if (isNrSupported()) {
235             return (preferredNetworkSetting
236                     == RadioAccessFamily.getRafFromNetworkType(
237                     RILConstants.NETWORK_MODE_NR_LTE_CDMA_EVDO_GSM_WCDMA));
238         } else {
239             return (preferredNetworkSetting == RadioAccessFamily.getRafFromNetworkType(
240                     RILConstants.NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA));
241         }
242     }
243 
isNrSupported()244     private boolean isNrSupported() {
245         Context context = mPhone.getContext();
246         TelephonyManager tm = ((TelephonyManager) context.getSystemService(
247                 Context.TELEPHONY_SERVICE)).createForSubscriptionId(mPhone.getSubId());
248 
249         boolean isCarrierConfigEnabled = isCarrierConfigEnableNr(context);
250         boolean isRadioAccessFamilySupported = checkSupportedBitmask(
251                 tm.getSupportedRadioAccessFamily(), TelephonyManager.NETWORK_TYPE_BITMASK_NR);
252         boolean isNrNetworkTypeAllowed = checkSupportedBitmask(
253                 tm.getAllowedNetworkTypesForReason(
254                         TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_CARRIER),
255                 TelephonyManager.NETWORK_TYPE_BITMASK_NR);
256 
257         Rlog.i(LOG_TAG, "isNrSupported: " + " carrierConfigEnabled: " + isCarrierConfigEnabled
258                 + ", AccessFamilySupported: " + isRadioAccessFamilySupported
259                 + ", isNrNetworkTypeAllowed: " + isNrNetworkTypeAllowed);
260 
261         return (isCarrierConfigEnabled && isRadioAccessFamilySupported && isNrNetworkTypeAllowed);
262     }
263 
isCarrierConfigEnableNr(Context context)264     private boolean isCarrierConfigEnableNr(Context context) {
265         CarrierConfigManager carrierConfigManager = (CarrierConfigManager)
266                 context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
267         if (carrierConfigManager == null) {
268             Rlog.e(LOG_TAG, "isCarrierConfigEnableNr: CarrierConfigManager is null");
269             return false;
270         }
271         PersistableBundle config = carrierConfigManager.getConfigForSubId(mPhone.getSubId());
272         if (config == null) {
273             Rlog.e(LOG_TAG, "isCarrierConfigEnableNr: Cannot get config " + mPhone.getSubId());
274             return false;
275         }
276         int[] nrAvailabilities = config.getIntArray(
277                 CarrierConfigManager.KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY);
278         return !ArrayUtils.isEmpty(nrAvailabilities);
279     }
280 
checkSupportedBitmask(@etworkTypeBitMask long supportedBitmask, @NetworkTypeBitMask long targetBitmask)281     private boolean checkSupportedBitmask(@NetworkTypeBitMask long supportedBitmask,
282             @NetworkTypeBitMask long targetBitmask) {
283         return (targetBitmask & supportedBitmask) == targetBitmask;
284     }
285 
handleConfigChanges()286     private void handleConfigChanges() {
287         for (Map.Entry<Integer, NotificationType> entry : mNotificationTypeMap.entrySet()) {
288             NotificationType notificationType = entry.getValue();
289             evaluateSendingMessageOrCancelNotification(notificationType);
290         }
291     }
292 
handleAllowedNetworkTypeChanged()293     private void handleAllowedNetworkTypeChanged() {
294         NotificationType notificationType = mNotificationTypeMap.get(NOTIFICATION_PREF_NETWORK);
295         if (notificationType != null) {
296             evaluateSendingMessageOrCancelNotification(notificationType);
297         }
298     }
299 
handleImsCapabilitiesChanged()300     private void handleImsCapabilitiesChanged() {
301         NotificationType notificationType = mNotificationTypeMap
302                 .get(NOTIFICATION_EMERGENCY_NETWORK);
303         if (notificationType != null) {
304             evaluateSendingMessageOrCancelNotification(notificationType);
305         }
306     }
307 
evaluateSendingMessageOrCancelNotification(NotificationType notificationType)308     private void evaluateSendingMessageOrCancelNotification(NotificationType notificationType) {
309         if (evaluateSendingMessage(notificationType)) {
310             Message notificationMsg = obtainMessage(notificationType.getTypeId(), null);
311             Rlog.i(LOG_TAG, "starting timer for notifications." + notificationType.getTypeId());
312             sendMessageDelayed(notificationMsg, getDelay(notificationType));
313         } else {
314             cancelNotification(notificationType);
315             Rlog.i(LOG_TAG, "canceling notifications: " + notificationType.getTypeId());
316         }
317     }
318 
319     /**
320      * This method adds a level of indirection, and was created so we can unit the class.
321      **/
322     @VisibleForTesting
evaluateSendingMessage(NotificationType notificationType)323     public boolean evaluateSendingMessage(NotificationType notificationType) {
324         return notificationType.sendMessage();
325     }
326 
327     /**
328      * This method adds a level of indirection, and was created so we can unit the class.
329      **/
330     @VisibleForTesting
getDelay(NotificationType notificationType)331     public int getDelay(NotificationType notificationType) {
332         return notificationType.getDelay();
333     }
334 
335     /**
336      * This method adds a level of indirection, and was created so we can unit the class.
337      **/
338     @VisibleForTesting
getNotificationBuilder(NotificationType notificationType)339     public Notification.Builder getNotificationBuilder(NotificationType notificationType) {
340         return notificationType.getNotificationBuilder();
341     }
342 
343     /**
344      * This method adds a level of indirection, and was created so we can unit the class.
345      **/
346     @VisibleForTesting
getNotificationManager(Context context)347     public NotificationManager getNotificationManager(Context context) {
348         return (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
349     }
350 
351     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
352         @Override
353         public void onReceive(Context context, Intent intent) {
354             CarrierConfigManager carrierConfigManager = (CarrierConfigManager)
355                     context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
356             PersistableBundle b = carrierConfigManager.getConfigForSubId(mPhone.getSubId());
357 
358             for (Map.Entry<Integer, NotificationType> entry : mNotificationTypeMap.entrySet()) {
359                 NotificationType notificationType = entry.getValue();
360                 notificationType.setDelay(b);
361             }
362             handleConfigChanges();
363         }
364     };
365 
366     /**
367      * Post a notification to the NotificationManager for changing network type.
368      */
369     @VisibleForTesting
sendNotification(NotificationType notificationType)370     public void sendNotification(NotificationType notificationType) {
371         if (!evaluateSendingMessage(notificationType)) {
372             return;
373         }
374 
375         Context context = mPhone.getContext();
376         Notification.Builder builder = getNotificationBuilder(notificationType);
377         // set some common attributes
378         builder.setWhen(System.currentTimeMillis())
379                 .setAutoCancel(true)
380                 .setSmallIcon(com.android.internal.R.drawable.stat_sys_warning)
381                 .setColor(context.getResources().getColor(
382                        com.android.internal.R.color.system_notification_accent_color));
383         getNotificationManager(context).notify(notificationType.getNotificationTag(),
384                 notificationType.getNotificationId(), builder.build());
385     }
386 
387     /**
388      * Cancel notifications if a registration is pending or has been sent.
389      **/
cancelNotification(NotificationType notificationType)390     public void cancelNotification(NotificationType notificationType) {
391         Context context = mPhone.getContext();
392         removeMessages(notificationType.getTypeId());
393         getNotificationManager(context).cancel(
394                 notificationType.getNotificationTag(), notificationType.getNotificationId());
395     }
396 
397     /**
398      * Dispose the CarrierServiceStateTracker.
399      */
dispose()400     public void dispose() {
401         unregisterAllowedNetworkTypesListener();
402     }
403 
404     /**
405      * Class that defines the different types of notifications.
406      */
407     public interface NotificationType {
408 
409         /**
410          * decides if the message should be sent, Returns boolean
411          **/
sendMessage()412         boolean sendMessage();
413 
414         /**
415          * returns the interval by which the message is delayed.
416          **/
getDelay()417         int getDelay();
418 
419         /** sets the interval by which the message is delayed.
420          * @param bundle PersistableBundle
421         **/
setDelay(PersistableBundle bundle)422         void setDelay(PersistableBundle bundle);
423 
424         /**
425          * returns notification type id.
426          **/
getTypeId()427         int getTypeId();
428 
429         /**
430          * returns notification id.
431          **/
getNotificationId()432         int getNotificationId();
433 
434         /**
435          * returns notification tag.
436          **/
getNotificationTag()437         String getNotificationTag();
438 
439         /**
440          * returns the notification builder, for the notification to be displayed.
441          **/
getNotificationBuilder()442         Notification.Builder getNotificationBuilder();
443     }
444 
445     /**
446      * Class that defines the network notification, which is shown when the phone cannot camp on
447      * a network, and has 'preferred mode' set to global.
448      */
449     public class PrefNetworkNotification implements NotificationType {
450 
451         private final int mTypeId;
452         private int mDelay = UNINITIALIZED_DELAY_VALUE;
453 
PrefNetworkNotification(int typeId)454         PrefNetworkNotification(int typeId) {
455             this.mTypeId = typeId;
456         }
457 
458         /** sets the interval by which the message is delayed.
459          * @param bundle PersistableBundle
460          **/
setDelay(PersistableBundle bundle)461         public void setDelay(PersistableBundle bundle) {
462             if (bundle == null) {
463                 Rlog.e(LOG_TAG, "bundle is null");
464                 return;
465             }
466             this.mDelay = bundle.getInt(
467                     CarrierConfigManager.KEY_PREF_NETWORK_NOTIFICATION_DELAY_INT);
468             Rlog.i(LOG_TAG, "reading time to delay notification pref network: " + mDelay);
469         }
470 
getDelay()471         public int getDelay() {
472             return mDelay;
473         }
474 
getTypeId()475         public int getTypeId() {
476             return mTypeId;
477         }
478 
getNotificationId()479         public int getNotificationId() {
480             return mPhone.getSubId();
481         }
482 
getNotificationTag()483         public String getNotificationTag() {
484             return PREF_NETWORK_NOTIFICATION_TAG;
485         }
486 
487         /**
488          * Contains logic on sending notifications.
489          */
sendMessage()490         public boolean sendMessage() {
491             Rlog.i(LOG_TAG, "PrefNetworkNotification: sendMessage() w/values: "
492                     + "," + isPhoneStillRegistered() + "," + mDelay + "," + isGlobalMode()
493                     + "," + mSST.isRadioOn());
494             if (mDelay == UNINITIALIZED_DELAY_VALUE || isPhoneStillRegistered() || isGlobalMode()
495                     || isRadioOffOrAirplaneMode()) {
496                 return false;
497             }
498             return true;
499         }
500 
501         /**
502          * Builds a partial notificaiton builder, and returns it.
503          */
getNotificationBuilder()504         public Notification.Builder getNotificationBuilder() {
505             Context context = mPhone.getContext();
506             Intent notificationIntent = new Intent(Settings.ACTION_DATA_ROAMING_SETTINGS);
507             notificationIntent.putExtra("expandable", true);
508             PendingIntent settingsIntent = PendingIntent.getActivity(context, 0, notificationIntent,
509                     PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_IMMUTABLE);
510             Resources res = SubscriptionManager.getResourcesForSubId(context, mPhone.getSubId());
511             CharSequence title = res.getText(
512                     com.android.internal.R.string.NetworkPreferenceSwitchTitle);
513             CharSequence details = res.getText(
514                     com.android.internal.R.string.NetworkPreferenceSwitchSummary);
515             return new Notification.Builder(context)
516                     .setContentTitle(title)
517                     .setStyle(new Notification.BigTextStyle().bigText(details))
518                     .setContentText(details)
519                     .setChannelId(NotificationChannelController.CHANNEL_ID_ALERT)
520                     .setContentIntent(settingsIntent);
521         }
522     }
523 
524     /**
525      * Class that defines the emergency notification, which is shown when Wi-Fi Calling is
526      * available.
527      */
528     public class EmergencyNetworkNotification implements NotificationType {
529 
530         private final int mTypeId;
531         private int mDelay = UNINITIALIZED_DELAY_VALUE;
532 
EmergencyNetworkNotification(int typeId)533         EmergencyNetworkNotification(int typeId) {
534             this.mTypeId = typeId;
535         }
536 
537         /** sets the interval by which the message is delayed.
538          * @param bundle PersistableBundle
539          **/
setDelay(PersistableBundle bundle)540         public void setDelay(PersistableBundle bundle) {
541             if (bundle == null) {
542                 Rlog.e(LOG_TAG, "bundle is null");
543                 return;
544             }
545             this.mDelay = bundle.getInt(
546                     CarrierConfigManager.KEY_EMERGENCY_NOTIFICATION_DELAY_INT);
547             Rlog.i(LOG_TAG, "reading time to delay notification emergency: " + mDelay);
548         }
549 
getDelay()550         public int getDelay() {
551             return mDelay;
552         }
553 
getTypeId()554         public int getTypeId() {
555             return mTypeId;
556         }
557 
getNotificationId()558         public int getNotificationId() {
559             return mPhone.getSubId();
560         }
561 
getNotificationTag()562         public String getNotificationTag() {
563             return EMERGENCY_NOTIFICATION_TAG;
564         }
565 
566         /**
567          * Contains logic on sending notifications,
568          */
sendMessage()569         public boolean sendMessage() {
570             Rlog.i(LOG_TAG, "EmergencyNetworkNotification: sendMessage() w/values: "
571                     + "," + mDelay + "," + isPhoneRegisteredForWifiCalling() + ","
572                     + mSST.isRadioOn());
573             if (mDelay == UNINITIALIZED_DELAY_VALUE || !isPhoneRegisteredForWifiCalling()) {
574                 return false;
575             }
576             return true;
577         }
578 
579         /**
580          * Builds a partial notificaiton builder, and returns it.
581          */
getNotificationBuilder()582         public Notification.Builder getNotificationBuilder() {
583             Context context = mPhone.getContext();
584             Resources res = SubscriptionManager.getResourcesForSubId(context, mPhone.getSubId());
585             CharSequence title = res.getText(
586                     com.android.internal.R.string.EmergencyCallWarningTitle);
587             CharSequence details = res.getText(
588                     com.android.internal.R.string.EmergencyCallWarningSummary);
589             return new Notification.Builder(context)
590                     .setContentTitle(title)
591                     .setStyle(new Notification.BigTextStyle().bigText(details))
592                     .setContentText(details)
593                     .setFlag(Notification.FLAG_NO_CLEAR, true)
594                     .setChannelId(NotificationChannelController.CHANNEL_ID_WFC);
595         }
596     }
597 }
598