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.annotation.NonNull; 20 import android.app.Notification; 21 import android.app.NotificationManager; 22 import android.app.PendingIntent; 23 import android.content.BroadcastReceiver; 24 import android.content.Context; 25 import android.content.Intent; 26 import android.content.IntentFilter; 27 import android.content.SharedPreferences; 28 import android.content.pm.PackageManager; 29 import android.content.res.Resources; 30 import android.os.Handler; 31 import android.os.HandlerExecutor; 32 import android.os.Message; 33 import android.os.PersistableBundle; 34 import android.preference.PreferenceManager; 35 import android.provider.Settings; 36 import android.telephony.CarrierConfigManager; 37 import android.telephony.RadioAccessFamily; 38 import android.telephony.ServiceState; 39 import android.telephony.SubscriptionManager; 40 import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; 41 import android.telephony.TelephonyCallback; 42 import android.telephony.TelephonyManager; 43 import android.telephony.TelephonyManager.NetworkTypeBitMask; 44 45 import com.android.internal.annotations.VisibleForTesting; 46 import com.android.internal.telephony.flags.FeatureFlags; 47 import com.android.internal.telephony.util.ArrayUtils; 48 import com.android.internal.telephony.util.NotificationChannelController; 49 import com.android.telephony.Rlog; 50 51 import java.util.HashMap; 52 import java.util.Map; 53 54 /** 55 * This contains Carrier specific logic based on the states/events 56 * managed in ServiceStateTracker. 57 * {@hide} 58 */ 59 public class CarrierServiceStateTracker extends Handler { 60 private static final String LOG_TAG = "CSST"; 61 protected static final int CARRIER_EVENT_BASE = 100; 62 protected static final int CARRIER_EVENT_VOICE_REGISTRATION = CARRIER_EVENT_BASE + 1; 63 protected static final int CARRIER_EVENT_VOICE_DEREGISTRATION = CARRIER_EVENT_BASE + 2; 64 protected static final int CARRIER_EVENT_DATA_REGISTRATION = CARRIER_EVENT_BASE + 3; 65 protected static final int CARRIER_EVENT_DATA_DEREGISTRATION = CARRIER_EVENT_BASE + 4; 66 protected static final int CARRIER_EVENT_IMS_CAPABILITIES_CHANGED = CARRIER_EVENT_BASE + 5; 67 68 private static final int UNINITIALIZED_DELAY_VALUE = -1; 69 private Phone mPhone; 70 private ServiceStateTracker mSST; 71 private final Map<Integer, NotificationType> mNotificationTypeMap = new HashMap<>(); 72 private int mPreviousSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; 73 public static final int NOTIFICATION_PREF_NETWORK = 1000; 74 public static final int NOTIFICATION_EMERGENCY_NETWORK = 1001; 75 76 77 @VisibleForTesting 78 public static final String ACTION_NEVER_ASK_AGAIN = "SilenceNoWifiEmrgCallingNotification"; 79 public final NotificationActionReceiver mActionReceiver = new NotificationActionReceiver(); 80 81 @VisibleForTesting 82 public static final String EMERGENCY_NOTIFICATION_TAG = "EmergencyNetworkNotification"; 83 84 @VisibleForTesting 85 public static final String PREF_NETWORK_NOTIFICATION_TAG = "PrefNetworkNotification"; 86 87 private long mAllowedNetworkType = -1; 88 private AllowedNetworkTypesListener mAllowedNetworkTypesListener; 89 private TelephonyManager mTelephonyManager; 90 @NonNull private final FeatureFlags mFeatureFlags; 91 92 /** 93 * The listener for allowed network types changed 94 */ 95 @VisibleForTesting 96 public class AllowedNetworkTypesListener extends TelephonyCallback 97 implements TelephonyCallback.AllowedNetworkTypesListener { 98 @Override onAllowedNetworkTypesChanged(int reason, long newAllowedNetworkType)99 public void onAllowedNetworkTypesChanged(int reason, long newAllowedNetworkType) { 100 if (reason != TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER) { 101 return; 102 } 103 104 if (mAllowedNetworkType != newAllowedNetworkType) { 105 mAllowedNetworkType = newAllowedNetworkType; 106 handleAllowedNetworkTypeChanged(); 107 } 108 } 109 } 110 CarrierServiceStateTracker(Phone phone, ServiceStateTracker sst, @NonNull FeatureFlags featureFlags)111 public CarrierServiceStateTracker(Phone phone, ServiceStateTracker sst, 112 @NonNull FeatureFlags featureFlags) { 113 mFeatureFlags = featureFlags; 114 this.mPhone = phone; 115 this.mSST = sst; 116 mTelephonyManager = mPhone.getContext().getSystemService( 117 TelephonyManager.class).createForSubscriptionId(mPhone.getSubId()); 118 CarrierConfigManager ccm = mPhone.getContext().getSystemService(CarrierConfigManager.class); 119 ccm.registerCarrierConfigChangeListener( 120 mPhone.getContext().getMainExecutor(), 121 (slotIndex, subId, carrierId, specificCarrierId) -> { 122 if (slotIndex != mPhone.getPhoneId()) return; 123 124 Rlog.d(LOG_TAG, "onCarrierConfigChanged: slotIndex=" + slotIndex 125 + ", subId=" + subId + ", carrierId=" + carrierId); 126 127 // Only get carrier configs used for EmergencyNetworkNotification 128 // and PrefNetworkNotification 129 PersistableBundle b = 130 CarrierConfigManager.getCarrierConfigSubset( 131 mPhone.getContext(), 132 mPhone.getSubId(), 133 CarrierConfigManager.KEY_EMERGENCY_NOTIFICATION_DELAY_INT, 134 CarrierConfigManager.KEY_PREF_NETWORK_NOTIFICATION_DELAY_INT, 135 CarrierConfigManager.KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL); 136 if (b.isEmpty()) return; 137 138 for (Map.Entry<Integer, NotificationType> entry : 139 mNotificationTypeMap.entrySet()) { 140 NotificationType notificationType = entry.getValue(); 141 notificationType.setDelay(b); 142 notificationType.setEnabled(b); 143 } 144 handleConfigChanges(); 145 }); 146 147 // Listen for subscriber changes 148 SubscriptionManager.from(mPhone.getContext()).addOnSubscriptionsChangedListener( 149 new OnSubscriptionsChangedListener(this.getLooper()) { 150 @Override 151 public void onSubscriptionsChanged() { 152 int subId = mPhone.getSubId(); 153 if (mPreviousSubId != subId) { 154 mPreviousSubId = subId; 155 mTelephonyManager = mTelephonyManager.createForSubscriptionId( 156 mPhone.getSubId()); 157 registerAllowedNetworkTypesListener(); 158 } 159 } 160 }); 161 162 if (!mPhone.getContext().getPackageManager().hasSystemFeature( 163 PackageManager.FEATURE_WATCH)) { 164 registerNotificationTypes(); 165 } 166 167 mAllowedNetworkType = RadioAccessFamily.getNetworkTypeFromRaf( 168 (int) mPhone.getAllowedNetworkTypes( 169 TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER)); 170 mAllowedNetworkTypesListener = new AllowedNetworkTypesListener(); 171 registerAllowedNetworkTypesListener(); 172 173 if (mFeatureFlags.stopSpammingEmergencyNotification()) { 174 // register a receiver for notification actions 175 mPhone.getContext().registerReceiver( 176 mActionReceiver, 177 new IntentFilter(ACTION_NEVER_ASK_AGAIN), 178 Context.RECEIVER_NOT_EXPORTED); 179 } 180 } 181 182 /** 183 * Return preferred network mode listener 184 */ 185 @VisibleForTesting getAllowedNetworkTypesChangedListener()186 public AllowedNetworkTypesListener getAllowedNetworkTypesChangedListener() { 187 return mAllowedNetworkTypesListener; 188 } 189 registerAllowedNetworkTypesListener()190 private void registerAllowedNetworkTypesListener() { 191 int subId = mPhone.getSubId(); 192 unregisterAllowedNetworkTypesListener(); 193 if (SubscriptionManager.isValidSubscriptionId(subId)) { 194 if (mTelephonyManager != null) { 195 mTelephonyManager.registerTelephonyCallback(new HandlerExecutor(this), 196 mAllowedNetworkTypesListener); 197 } 198 } 199 } 200 unregisterAllowedNetworkTypesListener()201 private void unregisterAllowedNetworkTypesListener() { 202 mTelephonyManager.unregisterTelephonyCallback(mAllowedNetworkTypesListener); 203 } 204 205 /** 206 * Returns mNotificationTypeMap 207 */ 208 @VisibleForTesting getNotificationTypeMap()209 public Map<Integer, NotificationType> getNotificationTypeMap() { 210 return mNotificationTypeMap; 211 } 212 registerNotificationTypes()213 private void registerNotificationTypes() { 214 mNotificationTypeMap.put(NOTIFICATION_PREF_NETWORK, 215 new PrefNetworkNotification(NOTIFICATION_PREF_NETWORK)); 216 mNotificationTypeMap.put(NOTIFICATION_EMERGENCY_NETWORK, 217 new EmergencyNetworkNotification(NOTIFICATION_EMERGENCY_NETWORK)); 218 } 219 220 @Override handleMessage(Message msg)221 public void handleMessage(Message msg) { 222 switch (msg.what) { 223 case CARRIER_EVENT_VOICE_REGISTRATION: 224 case CARRIER_EVENT_DATA_REGISTRATION: 225 case CARRIER_EVENT_VOICE_DEREGISTRATION: 226 case CARRIER_EVENT_DATA_DEREGISTRATION: 227 handleConfigChanges(); 228 break; 229 case CARRIER_EVENT_IMS_CAPABILITIES_CHANGED: 230 handleImsCapabilitiesChanged(); 231 break; 232 case NOTIFICATION_EMERGENCY_NETWORK: 233 case NOTIFICATION_PREF_NETWORK: 234 Rlog.d(LOG_TAG, "sending notification after delay: " + msg.what); 235 NotificationType notificationType = mNotificationTypeMap.get(msg.what); 236 if (notificationType != null) { 237 sendNotification(notificationType); 238 } 239 break; 240 } 241 } 242 isPhoneStillRegistered()243 private boolean isPhoneStillRegistered() { 244 if (mSST.mSS == null) { 245 return true; //something has gone wrong, return true and not show the notification. 246 } 247 return (mSST.mSS.getState() == ServiceState.STATE_IN_SERVICE 248 || mSST.mSS.getDataRegistrationState() == ServiceState.STATE_IN_SERVICE); 249 } 250 isPhoneRegisteredForWifiCalling()251 private boolean isPhoneRegisteredForWifiCalling() { 252 Rlog.d(LOG_TAG, "isPhoneRegisteredForWifiCalling: " + mPhone.isWifiCallingEnabled()); 253 return mPhone.isWifiCallingEnabled(); 254 } 255 256 /** 257 * Returns true if the radio is off or in Airplane Mode else returns false. 258 */ 259 @VisibleForTesting isRadioOffOrAirplaneMode()260 public boolean isRadioOffOrAirplaneMode() { 261 Context context = mPhone.getContext(); 262 int airplaneMode = -1; 263 try { 264 airplaneMode = Settings.Global.getInt(context.getContentResolver(), 265 Settings.Global.AIRPLANE_MODE_ON, 0); 266 } catch (Exception e) { 267 Rlog.e(LOG_TAG, "Unable to get AIRPLACE_MODE_ON."); 268 return true; 269 } 270 return (!mSST.isRadioOn() || (airplaneMode != 0)); 271 } 272 273 /** 274 * Returns true if the preferred network is set to 'Global'. 275 */ isGlobalMode()276 private boolean isGlobalMode() { 277 int preferredNetworkSetting = -1; 278 try { 279 preferredNetworkSetting = PhoneFactory.calculatePreferredNetworkType( 280 mPhone.getPhoneId()); 281 } catch (Exception e) { 282 Rlog.e(LOG_TAG, "Unable to get PREFERRED_NETWORK_MODE."); 283 return true; 284 } 285 286 if (isNrSupported()) { 287 return (preferredNetworkSetting 288 == RadioAccessFamily.getRafFromNetworkType( 289 RILConstants.NETWORK_MODE_NR_LTE_CDMA_EVDO_GSM_WCDMA)); 290 } else { 291 return (preferredNetworkSetting == RadioAccessFamily.getRafFromNetworkType( 292 RILConstants.NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA)); 293 } 294 } 295 isNrSupported()296 private boolean isNrSupported() { 297 Context context = mPhone.getContext(); 298 TelephonyManager tm = ((TelephonyManager) context.getSystemService( 299 Context.TELEPHONY_SERVICE)).createForSubscriptionId(mPhone.getSubId()); 300 301 boolean isCarrierConfigEnabled = isCarrierConfigEnableNr(); 302 boolean isRadioAccessFamilySupported = checkSupportedBitmask( 303 tm.getSupportedRadioAccessFamily(), TelephonyManager.NETWORK_TYPE_BITMASK_NR); 304 boolean isNrNetworkTypeAllowed = checkSupportedBitmask( 305 tm.getAllowedNetworkTypesForReason( 306 TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_CARRIER), 307 TelephonyManager.NETWORK_TYPE_BITMASK_NR); 308 309 Rlog.i(LOG_TAG, "isNrSupported: " + " carrierConfigEnabled: " + isCarrierConfigEnabled 310 + ", AccessFamilySupported: " + isRadioAccessFamilySupported 311 + ", isNrNetworkTypeAllowed: " + isNrNetworkTypeAllowed); 312 313 return (isCarrierConfigEnabled && isRadioAccessFamilySupported && isNrNetworkTypeAllowed); 314 } 315 isCarrierConfigEnableNr()316 private boolean isCarrierConfigEnableNr() { 317 PersistableBundle config = 318 CarrierConfigManager.getCarrierConfigSubset( 319 mPhone.getContext(), 320 mPhone.getSubId(), 321 CarrierConfigManager.KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY); 322 if (config.isEmpty()) { 323 Rlog.e(LOG_TAG, "isCarrierConfigEnableNr: Cannot get config " + mPhone.getSubId()); 324 return false; 325 } 326 int[] nrAvailabilities = config.getIntArray( 327 CarrierConfigManager.KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY); 328 return !ArrayUtils.isEmpty(nrAvailabilities); 329 } 330 checkSupportedBitmask(@etworkTypeBitMask long supportedBitmask, @NetworkTypeBitMask long targetBitmask)331 private boolean checkSupportedBitmask(@NetworkTypeBitMask long supportedBitmask, 332 @NetworkTypeBitMask long targetBitmask) { 333 return (targetBitmask & supportedBitmask) == targetBitmask; 334 } 335 handleConfigChanges()336 private void handleConfigChanges() { 337 for (Map.Entry<Integer, NotificationType> entry : mNotificationTypeMap.entrySet()) { 338 NotificationType notificationType = entry.getValue(); 339 evaluateSendingMessageOrCancelNotification(notificationType); 340 } 341 } 342 handleAllowedNetworkTypeChanged()343 private void handleAllowedNetworkTypeChanged() { 344 NotificationType notificationType = mNotificationTypeMap.get(NOTIFICATION_PREF_NETWORK); 345 if (notificationType != null) { 346 evaluateSendingMessageOrCancelNotification(notificationType); 347 } 348 } 349 handleImsCapabilitiesChanged()350 private void handleImsCapabilitiesChanged() { 351 NotificationType notificationType = mNotificationTypeMap 352 .get(NOTIFICATION_EMERGENCY_NETWORK); 353 if (notificationType != null) { 354 evaluateSendingMessageOrCancelNotification(notificationType); 355 } 356 } 357 evaluateSendingMessageOrCancelNotification(NotificationType notificationType)358 private void evaluateSendingMessageOrCancelNotification(NotificationType notificationType) { 359 if (evaluateSendingMessage(notificationType)) { 360 Message notificationMsg = obtainMessage(notificationType.getTypeId(), null); 361 Rlog.i(LOG_TAG, "starting timer for notifications." + notificationType.getTypeId()); 362 sendMessageDelayed(notificationMsg, getDelay(notificationType)); 363 } else { 364 cancelNotification(notificationType); 365 Rlog.i(LOG_TAG, "canceling notifications: " + notificationType.getTypeId()); 366 } 367 } 368 369 /** 370 * This method adds a level of indirection, and was created so we can unit the class. 371 **/ 372 @VisibleForTesting evaluateSendingMessage(NotificationType notificationType)373 public boolean evaluateSendingMessage(NotificationType notificationType) { 374 return notificationType.sendMessage(); 375 } 376 377 /** 378 * This method adds a level of indirection, and was created so we can unit the class. 379 **/ 380 @VisibleForTesting getDelay(NotificationType notificationType)381 public int getDelay(NotificationType notificationType) { 382 return notificationType.getDelay(); 383 } 384 385 /** 386 * This method adds a level of indirection, and was created so we can unit the class. 387 **/ 388 @VisibleForTesting getNotificationBuilder(NotificationType notificationType)389 public Notification.Builder getNotificationBuilder(NotificationType notificationType) { 390 return notificationType.getNotificationBuilder(); 391 } 392 393 /** 394 * This method adds a level of indirection, and was created so we can unit the class. 395 **/ 396 @VisibleForTesting getNotificationManager(Context context)397 public NotificationManager getNotificationManager(Context context) { 398 return (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); 399 } 400 401 /** 402 * Post a notification to the NotificationManager for changing network type. 403 */ 404 @VisibleForTesting sendNotification(NotificationType notificationType)405 public void sendNotification(NotificationType notificationType) { 406 Context context = mPhone.getContext(); 407 408 if (!evaluateSendingMessage(notificationType)) { 409 return; 410 } 411 412 if (mFeatureFlags.stopSpammingEmergencyNotification() 413 && shouldSilenceEmrgNetNotif(notificationType, context)) { 414 Rlog.i(LOG_TAG, "sendNotification: silencing NOTIFICATION_EMERGENCY_NETWORK"); 415 return; 416 } 417 418 Notification.Builder builder = getNotificationBuilder(notificationType); 419 // set some common attributes 420 builder.setWhen(System.currentTimeMillis()) 421 .setShowWhen(true) 422 .setAutoCancel(true) 423 .setSmallIcon(com.android.internal.R.drawable.stat_sys_warning) 424 .setColor(context.getResources().getColor( 425 com.android.internal.R.color.system_notification_accent_color)); 426 getNotificationManager(context).notify(notificationType.getNotificationTag(), 427 notificationType.getNotificationId(), builder.build()); 428 } 429 430 /** 431 * This helper checks if the user has set a flag to silence the notification permanently 432 */ shouldSilenceEmrgNetNotif(NotificationType notificationType, Context context)433 private boolean shouldSilenceEmrgNetNotif(NotificationType notificationType, Context context) { 434 return notificationType.getTypeId() == NOTIFICATION_EMERGENCY_NETWORK 435 && PreferenceManager.getDefaultSharedPreferences(context) 436 .getBoolean(ACTION_NEVER_ASK_AGAIN, false); 437 } 438 439 /** 440 * Cancel notifications if a registration is pending or has been sent. 441 **/ cancelNotification(NotificationType notificationType)442 public void cancelNotification(NotificationType notificationType) { 443 Context context = mPhone.getContext(); 444 removeMessages(notificationType.getTypeId()); 445 getNotificationManager(context).cancel( 446 notificationType.getNotificationTag(), notificationType.getNotificationId()); 447 } 448 449 /** 450 * Dispose the CarrierServiceStateTracker. 451 */ dispose()452 public void dispose() { 453 unregisterAllowedNetworkTypesListener(); 454 } 455 456 /** 457 * Class that defines the different types of notifications. 458 */ 459 public interface NotificationType { 460 461 /** 462 * decides if the message should be sent, Returns boolean 463 **/ sendMessage()464 boolean sendMessage(); 465 466 /** 467 * returns the interval by which the message is delayed. 468 **/ getDelay()469 int getDelay(); 470 471 /** sets the interval by which the message is delayed. 472 * @param bundle PersistableBundle 473 **/ setDelay(PersistableBundle bundle)474 void setDelay(PersistableBundle bundle); 475 476 /** 477 * Checks whether this Notification is enabled. 478 * @return {@code true} if this Notification is enabled, false otherwise 479 */ isEnabled()480 boolean isEnabled(); 481 482 /** 483 * Sets whether this Notification is enabled. If disabled, it will not build notification. 484 * @param bundle PersistableBundle 485 */ setEnabled(PersistableBundle bundle)486 void setEnabled(PersistableBundle bundle); 487 488 /** 489 * returns notification type id. 490 **/ getTypeId()491 int getTypeId(); 492 493 /** 494 * returns notification id. 495 **/ getNotificationId()496 int getNotificationId(); 497 498 /** 499 * returns notification tag. 500 **/ getNotificationTag()501 String getNotificationTag(); 502 503 /** 504 * returns the notification builder, for the notification to be displayed. 505 **/ getNotificationBuilder()506 Notification.Builder getNotificationBuilder(); 507 } 508 509 /** 510 * Class that defines the network notification, which is shown when the phone cannot camp on 511 * a network, and has 'preferred mode' set to global. 512 */ 513 public class PrefNetworkNotification implements NotificationType { 514 515 private final int mTypeId; 516 private int mDelay = UNINITIALIZED_DELAY_VALUE; 517 private boolean mEnabled = false; 518 PrefNetworkNotification(int typeId)519 PrefNetworkNotification(int typeId) { 520 this.mTypeId = typeId; 521 } 522 523 /** sets the interval by which the message is delayed. 524 * @param bundle PersistableBundle 525 **/ setDelay(PersistableBundle bundle)526 public void setDelay(PersistableBundle bundle) { 527 if (bundle == null) { 528 Rlog.e(LOG_TAG, "bundle is null"); 529 return; 530 } 531 this.mDelay = bundle.getInt( 532 CarrierConfigManager.KEY_PREF_NETWORK_NOTIFICATION_DELAY_INT); 533 Rlog.i(LOG_TAG, "reading time to delay notification pref network: " + mDelay); 534 } 535 getDelay()536 public int getDelay() { 537 return mDelay; 538 } 539 540 /** 541 * Checks whether this Notification is enabled. 542 * @return {@code true} if this Notification is enabled, false otherwise 543 */ isEnabled()544 public boolean isEnabled() { 545 return mEnabled; 546 } 547 548 /** 549 * Sets whether this Notification is enabled. If disabled, it will not build notification. 550 * @param bundle PersistableBundle 551 */ setEnabled(PersistableBundle bundle)552 public void setEnabled(PersistableBundle bundle) { 553 if (bundle == null) { 554 Rlog.e(LOG_TAG, "bundle is null"); 555 return; 556 } 557 mEnabled = !bundle.getBoolean( 558 CarrierConfigManager.KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL); 559 Rlog.i(LOG_TAG, "reading enabled notification pref network: " + mEnabled); 560 } 561 getTypeId()562 public int getTypeId() { 563 return mTypeId; 564 } 565 getNotificationId()566 public int getNotificationId() { 567 return mPhone.getSubId(); 568 } 569 getNotificationTag()570 public String getNotificationTag() { 571 return PREF_NETWORK_NOTIFICATION_TAG; 572 } 573 574 /** 575 * Contains logic on sending notifications. 576 */ sendMessage()577 public boolean sendMessage() { 578 Rlog.i(LOG_TAG, "PrefNetworkNotification: sendMessage() w/values: " 579 + "," + mEnabled + "," + isPhoneStillRegistered() + "," + mDelay 580 + "," + isGlobalMode() + "," + mSST.isRadioOn()); 581 if (!mEnabled || mDelay == UNINITIALIZED_DELAY_VALUE || isPhoneStillRegistered() 582 || isGlobalMode() || isRadioOffOrAirplaneMode()) { 583 return false; 584 } 585 return true; 586 } 587 588 /** 589 * Builds a partial notificaiton builder, and returns it. 590 */ getNotificationBuilder()591 public Notification.Builder getNotificationBuilder() { 592 Context context = mPhone.getContext(); 593 Intent notificationIntent = new Intent(Settings.ACTION_DATA_ROAMING_SETTINGS); 594 notificationIntent.putExtra("expandable", true); 595 PendingIntent settingsIntent = PendingIntent.getActivity(context, 0, notificationIntent, 596 PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_IMMUTABLE); 597 Resources res = SubscriptionManager.getResourcesForSubId(context, mPhone.getSubId()); 598 CharSequence title = res.getText( 599 com.android.internal.R.string.NetworkPreferenceSwitchTitle); 600 CharSequence details = res.getText( 601 com.android.internal.R.string.NetworkPreferenceSwitchSummary); 602 return new Notification.Builder(context) 603 .setContentTitle(title) 604 .setStyle(new Notification.BigTextStyle().bigText(details)) 605 .setContentText(details) 606 .setChannelId(NotificationChannelController.CHANNEL_ID_ALERT) 607 .setContentIntent(settingsIntent); 608 } 609 } 610 611 /** 612 * Class that defines the emergency notification, which is shown when Wi-Fi Calling is 613 * available. 614 */ 615 public class EmergencyNetworkNotification implements NotificationType { 616 617 private final int mTypeId; 618 private int mDelay = UNINITIALIZED_DELAY_VALUE; 619 EmergencyNetworkNotification(int typeId)620 EmergencyNetworkNotification(int typeId) { 621 this.mTypeId = typeId; 622 } 623 624 /** sets the interval by which the message is delayed. 625 * @param bundle PersistableBundle 626 **/ setDelay(PersistableBundle bundle)627 public void setDelay(PersistableBundle bundle) { 628 if (bundle == null) { 629 Rlog.e(LOG_TAG, "bundle is null"); 630 return; 631 } 632 this.mDelay = bundle.getInt( 633 CarrierConfigManager.KEY_EMERGENCY_NOTIFICATION_DELAY_INT); 634 Rlog.i(LOG_TAG, "reading time to delay notification emergency: " + mDelay); 635 } 636 getDelay()637 public int getDelay() { 638 return mDelay; 639 } 640 641 /** 642 * Checks whether this Notification is enabled. 643 * @return {@code true} if this Notification is enabled, false otherwise 644 */ isEnabled()645 public boolean isEnabled() { 646 return true; 647 } 648 649 /** 650 * Sets whether this Notification is enabled. If disabled, it will not build notification. 651 * @param bundle PersistableBundle 652 */ setEnabled(PersistableBundle bundle)653 public void setEnabled(PersistableBundle bundle) { 654 // always allowed. There is no config to hide notifications. 655 } 656 getTypeId()657 public int getTypeId() { 658 return mTypeId; 659 } 660 getNotificationId()661 public int getNotificationId() { 662 return mPhone.getSubId(); 663 } 664 getNotificationTag()665 public String getNotificationTag() { 666 return EMERGENCY_NOTIFICATION_TAG; 667 } 668 669 /** 670 * Contains logic on sending notifications, 671 */ sendMessage()672 public boolean sendMessage() { 673 Rlog.i(LOG_TAG, "EmergencyNetworkNotification: sendMessage() w/values: " 674 + "," + mDelay + "," + isPhoneRegisteredForWifiCalling() + "," 675 + mSST.isRadioOn()); 676 if (mDelay == UNINITIALIZED_DELAY_VALUE || !isPhoneRegisteredForWifiCalling()) { 677 return false; 678 } 679 return true; 680 } 681 682 /** 683 * Builds a partial notificaiton builder, and returns it. 684 */ getNotificationBuilder()685 public Notification.Builder getNotificationBuilder() { 686 Context context = mPhone.getContext(); 687 Resources res = SubscriptionManager.getResourcesForSubId(context, mPhone.getSubId()); 688 CharSequence title = res.getText( 689 com.android.internal.R.string.EmergencyCallWarningTitle); 690 CharSequence details = res.getText( 691 com.android.internal.R.string.EmergencyCallWarningSummary); 692 if (mFeatureFlags.stopSpammingEmergencyNotification()) { 693 return new Notification.Builder(context) 694 .setContentTitle(title) 695 .setStyle(new Notification.BigTextStyle().bigText(details)) 696 .setContentText(details) 697 .setOngoing(true) 698 .setActions(createDoNotShowAgainAction(context)) 699 .setChannelId(NotificationChannelController.CHANNEL_ID_WFC); 700 } else { 701 return new Notification.Builder(context) 702 .setContentTitle(title) 703 .setStyle(new Notification.BigTextStyle().bigText(details)) 704 .setContentText(details) 705 .setOngoing(true) 706 .setChannelId(NotificationChannelController.CHANNEL_ID_WFC); 707 } 708 } 709 710 /** 711 * add a button to the notification that has a broadcast intent embedded to silence the 712 * notification 713 */ createDoNotShowAgainAction(Context context)714 private Notification.Action createDoNotShowAgainAction(Context context) { 715 final PendingIntent pendingIntent = PendingIntent.getBroadcast( 716 context, 717 0, 718 new Intent(ACTION_NEVER_ASK_AGAIN), 719 PendingIntent.FLAG_IMMUTABLE); 720 return new Notification.Action.Builder(null, "Do Not Show Again", 721 pendingIntent).build(); 722 } 723 } 724 725 /** 726 * This receiver listens to notification actions and can be utilized to do things like silence 727 * a notification that is spammy. 728 */ 729 public class NotificationActionReceiver extends BroadcastReceiver { 730 @Override onReceive(Context context, Intent intent)731 public void onReceive(Context context, Intent intent) { 732 if (intent.getAction().equals(ACTION_NEVER_ASK_AGAIN)) { 733 Rlog.i(LOG_TAG, "NotificationActionReceiver: ACTION_NEVER_ASK_AGAIN"); 734 // insert a key to silence future notifications 735 SharedPreferences.Editor editor = 736 PreferenceManager.getDefaultSharedPreferences(context).edit(); 737 editor.putBoolean(ACTION_NEVER_ASK_AGAIN, true); 738 editor.apply(); 739 // Note: If another action is added, unregistering here should be removed. However, 740 // since there is no longer a reason to broadcasts, cleanup mActionReceiver. 741 context.unregisterReceiver(mActionReceiver); 742 } 743 } 744 } 745 } 746