1 /* 2 * Copyright (C) 2020 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.content.BroadcastReceiver; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.content.IntentFilter; 23 import android.os.AsyncResult; 24 import android.os.Message; 25 import android.os.PersistableBundle; 26 import android.telephony.AccessNetworkConstants; 27 import android.telephony.Annotation; 28 import android.telephony.CarrierConfigManager; 29 import android.telephony.NetworkRegistrationInfo; 30 import android.telephony.RadioAccessFamily; 31 import android.telephony.ServiceState; 32 import android.telephony.SubscriptionManager; 33 import android.telephony.TelephonyDisplayInfo; 34 import android.telephony.TelephonyManager; 35 import android.text.TextUtils; 36 37 import com.android.internal.telephony.dataconnection.DcController; 38 import com.android.internal.telephony.dataconnection.DcController.PhysicalLinkState; 39 import com.android.internal.util.IState; 40 import com.android.internal.util.IndentingPrintWriter; 41 import com.android.internal.util.State; 42 import com.android.internal.util.StateMachine; 43 import com.android.telephony.Rlog; 44 45 import java.io.FileDescriptor; 46 import java.io.PrintWriter; 47 import java.util.ArrayList; 48 import java.util.HashMap; 49 import java.util.List; 50 import java.util.Map; 51 import java.util.regex.Matcher; 52 import java.util.regex.Pattern; 53 54 /** 55 * The NetworkTypeController evaluates the override network type of {@link TelephonyDisplayInfo} 56 * and sends it to {@link DisplayInfoController}. The override network type can replace the signal 57 * icon displayed on the status bar. It is affected by changes in data RAT, NR state, NR frequency, 58 * data activity, physical channel config, and carrier configurations. Based on carrier configs, 59 * NetworkTypeController also allows timers between various 5G states to prevent flickering. 60 */ 61 public class NetworkTypeController extends StateMachine { 62 private static final boolean DBG = true; 63 private static final String TAG = "NetworkTypeController"; 64 private static final String ICON_5G = "5g"; 65 private static final String ICON_5G_PLUS = "5g_plus"; 66 private static final String STATE_CONNECTED_MMWAVE = "connected_mmwave"; 67 private static final String STATE_CONNECTED = "connected"; 68 private static final String STATE_NOT_RESTRICTED_RRC_IDLE = "not_restricted_rrc_idle"; 69 private static final String STATE_NOT_RESTRICTED_RRC_CON = "not_restricted_rrc_con"; 70 private static final String STATE_RESTRICTED = "restricted"; 71 private static final String STATE_ANY = "any"; 72 private static final String STATE_LEGACY = "legacy"; 73 private static final String[] ALL_STATES = { STATE_CONNECTED_MMWAVE, STATE_CONNECTED, 74 STATE_NOT_RESTRICTED_RRC_IDLE, STATE_NOT_RESTRICTED_RRC_CON, STATE_RESTRICTED, 75 STATE_LEGACY }; 76 77 /** Stop all timers and go to current state. */ 78 public static final int EVENT_UPDATE = 0; 79 /** Quit after processing all existing messages. */ 80 public static final int EVENT_QUIT = 1; 81 private static final int EVENT_DATA_RAT_CHANGED = 2; 82 private static final int EVENT_NR_STATE_CHANGED = 3; 83 private static final int EVENT_NR_FREQUENCY_CHANGED = 4; 84 private static final int EVENT_PHYSICAL_LINK_STATE_CHANGED = 5; 85 private static final int EVENT_PHYSICAL_CHANNEL_CONFIG_NOTIF_CHANGED = 6; 86 private static final int EVENT_CARRIER_CONFIG_CHANGED = 7; 87 private static final int EVENT_PRIMARY_TIMER_EXPIRED = 8; 88 private static final int EVENT_SECONDARY_TIMER_EXPIRED = 9; 89 private static final int EVENT_RADIO_OFF_OR_UNAVAILABLE = 10; 90 private static final int EVENT_PREFERRED_NETWORK_MODE_CHANGED = 11; 91 private static final int EVENT_INITIALIZE = 12; 92 // events that don't reset the timer 93 private static final int[] ALL_EVENTS = { EVENT_DATA_RAT_CHANGED, EVENT_NR_STATE_CHANGED, 94 EVENT_NR_FREQUENCY_CHANGED, EVENT_PHYSICAL_LINK_STATE_CHANGED, 95 EVENT_PHYSICAL_CHANNEL_CONFIG_NOTIF_CHANGED, EVENT_PRIMARY_TIMER_EXPIRED, 96 EVENT_SECONDARY_TIMER_EXPIRED}; 97 98 private static final String[] sEvents = new String[EVENT_INITIALIZE + 1]; 99 static { 100 sEvents[EVENT_UPDATE] = "EVENT_UPDATE"; 101 sEvents[EVENT_QUIT] = "EVENT_QUIT"; 102 sEvents[EVENT_DATA_RAT_CHANGED] = "EVENT_DATA_RAT_CHANGED"; 103 sEvents[EVENT_NR_STATE_CHANGED] = "EVENT_NR_STATE_CHANGED"; 104 sEvents[EVENT_NR_FREQUENCY_CHANGED] = "EVENT_NR_FREQUENCY_CHANGED"; 105 sEvents[EVENT_PHYSICAL_LINK_STATE_CHANGED] = "EVENT_PHYSICAL_LINK_STATE_CHANGED"; 106 sEvents[EVENT_PHYSICAL_CHANNEL_CONFIG_NOTIF_CHANGED] = 107 "EVENT_PHYSICAL_CHANNEL_CONFIG_NOTIF_CHANGED"; 108 sEvents[EVENT_CARRIER_CONFIG_CHANGED] = "EVENT_CARRIER_CONFIG_CHANGED"; 109 sEvents[EVENT_PRIMARY_TIMER_EXPIRED] = "EVENT_PRIMARY_TIMER_EXPIRED"; 110 sEvents[EVENT_SECONDARY_TIMER_EXPIRED] = "EVENT_SECONDARY_TIMER_EXPIRED"; 111 sEvents[EVENT_RADIO_OFF_OR_UNAVAILABLE] = "EVENT_RADIO_OFF_OR_UNAVAILABLE"; 112 sEvents[EVENT_PREFERRED_NETWORK_MODE_CHANGED] = "EVENT_PREFERRED_NETWORK_MODE_CHANGED"; 113 sEvents[EVENT_INITIALIZE] = "EVENT_INITIALIZE"; 114 } 115 116 private final Phone mPhone; 117 private final DisplayInfoController mDisplayInfoController; 118 private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { 119 @Override 120 public void onReceive(Context context, Intent intent) { 121 if (intent.getAction().equals(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED) 122 && intent.getIntExtra(SubscriptionManager.EXTRA_SLOT_INDEX, 123 SubscriptionManager.INVALID_PHONE_INDEX) == mPhone.getPhoneId() 124 && !intent.getBooleanExtra(CarrierConfigManager.EXTRA_REBROADCAST_ON_UNLOCK, 125 false)) { 126 sendMessage(EVENT_CARRIER_CONFIG_CHANGED); 127 } 128 } 129 }; 130 131 private Map<String, OverrideTimerRule> mOverrideTimerRules = new HashMap<>(); 132 private String mLteEnhancedPattern = ""; 133 private int mOverrideNetworkType; 134 private boolean mIsPhysicalChannelConfigOn; 135 private boolean mIsPrimaryTimerActive; 136 private boolean mIsSecondaryTimerActive; 137 private boolean mIsTimerResetEnabledForLegacyStateRRCIdle; 138 private String mPrimaryTimerState; 139 private String mSecondaryTimerState; 140 private String mPreviousState; 141 private @PhysicalLinkState int mPhysicalLinkState; 142 143 /** 144 * NetworkTypeController constructor. 145 * 146 * @param phone Phone object. 147 * @param displayInfoController DisplayInfoController to send override network types to. 148 */ NetworkTypeController(Phone phone, DisplayInfoController displayInfoController)149 public NetworkTypeController(Phone phone, DisplayInfoController displayInfoController) { 150 super(TAG, displayInfoController); 151 mPhone = phone; 152 mDisplayInfoController = displayInfoController; 153 mOverrideNetworkType = TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE; 154 mIsPhysicalChannelConfigOn = true; 155 addState(mDefaultState); 156 addState(mLegacyState, mDefaultState); 157 addState(mIdleState, mDefaultState); 158 addState(mLteConnectedState, mDefaultState); 159 addState(mNrConnectedState, mDefaultState); 160 setInitialState(mDefaultState); 161 start(); 162 sendMessage(EVENT_INITIALIZE); 163 } 164 165 /** 166 * @return The current override network type, used to create TelephonyDisplayInfo in 167 * DisplayInfoController. 168 */ getOverrideNetworkType()169 public @Annotation.OverrideNetworkType int getOverrideNetworkType() { 170 return mOverrideNetworkType; 171 } 172 registerForAllEvents()173 private void registerForAllEvents() { 174 mPhone.registerForRadioOffOrNotAvailable(getHandler(), 175 EVENT_RADIO_OFF_OR_UNAVAILABLE, null); 176 mPhone.registerForPreferredNetworkTypeChanged(getHandler(), 177 EVENT_PREFERRED_NETWORK_MODE_CHANGED, null); 178 mPhone.getServiceStateTracker().registerForDataRegStateOrRatChanged( 179 AccessNetworkConstants.TRANSPORT_TYPE_WWAN, getHandler(), 180 EVENT_DATA_RAT_CHANGED, null); 181 mPhone.getDcTracker(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) 182 .registerForPhysicalLinkStateChanged(getHandler(), 183 EVENT_PHYSICAL_LINK_STATE_CHANGED); 184 mPhone.getServiceStateTracker().registerForNrStateChanged(getHandler(), 185 EVENT_NR_STATE_CHANGED, null); 186 mPhone.getServiceStateTracker().registerForNrFrequencyChanged(getHandler(), 187 EVENT_NR_FREQUENCY_CHANGED, null); 188 mPhone.getDeviceStateMonitor().registerForPhysicalChannelConfigNotifChanged(getHandler(), 189 EVENT_PHYSICAL_CHANNEL_CONFIG_NOTIF_CHANGED, null); 190 IntentFilter filter = new IntentFilter(); 191 filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); 192 mPhone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone); 193 } 194 unRegisterForAllEvents()195 private void unRegisterForAllEvents() { 196 mPhone.unregisterForRadioOffOrNotAvailable(getHandler()); 197 mPhone.unregisterForPreferredNetworkTypeChanged(getHandler()); 198 mPhone.getServiceStateTracker().unregisterForDataRegStateOrRatChanged( 199 AccessNetworkConstants.TRANSPORT_TYPE_WWAN, getHandler()); 200 mPhone.getServiceStateTracker().unregisterForNrStateChanged(getHandler()); 201 mPhone.getServiceStateTracker().unregisterForNrFrequencyChanged(getHandler()); 202 mPhone.getDeviceStateMonitor().unregisterForPhysicalChannelConfigNotifChanged(getHandler()); 203 mPhone.getContext().unregisterReceiver(mIntentReceiver); 204 } 205 parseCarrierConfigs()206 private void parseCarrierConfigs() { 207 String nrIconConfiguration = CarrierConfigManager.getDefaultConfig().getString( 208 CarrierConfigManager.KEY_5G_ICON_CONFIGURATION_STRING); 209 String overrideTimerRule = CarrierConfigManager.getDefaultConfig().getString( 210 CarrierConfigManager.KEY_5G_ICON_DISPLAY_GRACE_PERIOD_STRING); 211 String overrideSecondaryTimerRule = CarrierConfigManager.getDefaultConfig().getString( 212 CarrierConfigManager.KEY_5G_ICON_DISPLAY_SECONDARY_GRACE_PERIOD_STRING); 213 mLteEnhancedPattern = CarrierConfigManager.getDefaultConfig().getString( 214 CarrierConfigManager.KEY_SHOW_CARRIER_DATA_ICON_PATTERN_STRING); 215 mIsTimerResetEnabledForLegacyStateRRCIdle = 216 CarrierConfigManager.getDefaultConfig().getBoolean( 217 CarrierConfigManager.KEY_NR_TIMERS_RESET_IF_NON_ENDC_AND_RRC_IDLE_BOOL); 218 219 CarrierConfigManager configManager = (CarrierConfigManager) mPhone.getContext() 220 .getSystemService(Context.CARRIER_CONFIG_SERVICE); 221 if (configManager != null) { 222 PersistableBundle b = configManager.getConfigForSubId(mPhone.getSubId()); 223 if (b != null) { 224 if (b.getString(CarrierConfigManager.KEY_5G_ICON_CONFIGURATION_STRING) != null) { 225 nrIconConfiguration = b.getString( 226 CarrierConfigManager.KEY_5G_ICON_CONFIGURATION_STRING); 227 } 228 if (b.getString(CarrierConfigManager 229 .KEY_5G_ICON_DISPLAY_GRACE_PERIOD_STRING) != null) { 230 overrideTimerRule = b.getString( 231 CarrierConfigManager.KEY_5G_ICON_DISPLAY_GRACE_PERIOD_STRING); 232 } 233 if (b.getString(CarrierConfigManager 234 .KEY_5G_ICON_DISPLAY_SECONDARY_GRACE_PERIOD_STRING) != null) { 235 overrideSecondaryTimerRule = b.getString( 236 CarrierConfigManager.KEY_5G_ICON_DISPLAY_SECONDARY_GRACE_PERIOD_STRING); 237 } 238 if (b.getString(CarrierConfigManager 239 .KEY_SHOW_CARRIER_DATA_ICON_PATTERN_STRING) != null) { 240 mLteEnhancedPattern = b.getString( 241 CarrierConfigManager.KEY_SHOW_CARRIER_DATA_ICON_PATTERN_STRING); 242 } 243 mIsTimerResetEnabledForLegacyStateRRCIdle = b.getBoolean( 244 CarrierConfigManager.KEY_NR_TIMERS_RESET_IF_NON_ENDC_AND_RRC_IDLE_BOOL); 245 } 246 } 247 createTimerRules(nrIconConfiguration, overrideTimerRule, overrideSecondaryTimerRule); 248 } 249 createTimerRules(String icons, String timers, String secondaryTimers)250 private void createTimerRules(String icons, String timers, String secondaryTimers) { 251 Map<String, OverrideTimerRule> tempRules = new HashMap<>(); 252 if (!TextUtils.isEmpty(icons)) { 253 // Format: "STATE:ICON,STATE2:ICON2" 254 for (String pair : icons.trim().split(",")) { 255 String[] kv = (pair.trim().toLowerCase()).split(":"); 256 if (kv.length != 2) { 257 if (DBG) loge("Invalid 5G icon configuration, config = " + pair); 258 continue; 259 } 260 int icon = TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE; 261 if (kv[1].equals(ICON_5G)) { 262 icon = TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA; 263 } else if (kv[1].equals(ICON_5G_PLUS)) { 264 icon = TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE; 265 } else { 266 if (DBG) loge("Invalid 5G icon = " + kv[1]); 267 } 268 tempRules.put(kv[0], new OverrideTimerRule(kv[0], icon)); 269 } 270 } 271 // Ensure all states have an associated OverrideTimerRule and icon 272 for (String state : ALL_STATES) { 273 if (!tempRules.containsKey(state)) { 274 tempRules.put(state, new OverrideTimerRule( 275 state, TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE)); 276 } 277 } 278 279 if (!TextUtils.isEmpty(timers)) { 280 // Format: "FROM_STATE,TO_STATE,DURATION;FROM_STATE_2,TO_STATE_2,DURATION_2" 281 for (String triple : timers.trim().split(";")) { 282 String[] kv = (triple.trim().toLowerCase()).split(","); 283 if (kv.length != 3) { 284 if (DBG) loge("Invalid 5G icon timer configuration, config = " + triple); 285 continue; 286 } 287 int duration; 288 try { 289 duration = Integer.parseInt(kv[2]); 290 } catch (NumberFormatException e) { 291 continue; 292 } 293 if (kv[0].equals(STATE_ANY)) { 294 for (String state : ALL_STATES) { 295 OverrideTimerRule node = tempRules.get(state); 296 node.addTimer(kv[1], duration); 297 } 298 } else { 299 OverrideTimerRule node = tempRules.get(kv[0]); 300 node.addTimer(kv[1], duration); 301 } 302 } 303 } 304 305 if (!TextUtils.isEmpty(secondaryTimers)) { 306 // Format: "PRIMARY_STATE,TO_STATE,DURATION;PRIMARY_STATE_2,TO_STATE_2,DURATION_2" 307 for (String triple : secondaryTimers.trim().split(";")) { 308 String[] kv = (triple.trim().toLowerCase()).split(","); 309 if (kv.length != 3) { 310 if (DBG) { 311 loge("Invalid 5G icon secondary timer configuration, config = " + triple); 312 } 313 continue; 314 } 315 int duration; 316 try { 317 duration = Integer.parseInt(kv[2]); 318 } catch (NumberFormatException e) { 319 continue; 320 } 321 if (kv[0].equals(STATE_ANY)) { 322 for (String state : ALL_STATES) { 323 OverrideTimerRule node = tempRules.get(state); 324 node.addSecondaryTimer(kv[1], duration); 325 } 326 } else { 327 OverrideTimerRule node = tempRules.get(kv[0]); 328 node.addSecondaryTimer(kv[1], duration); 329 } 330 } 331 } 332 333 mOverrideTimerRules = tempRules; 334 if (DBG) log("mOverrideTimerRules: " + mOverrideTimerRules); 335 } 336 updateOverrideNetworkType()337 private void updateOverrideNetworkType() { 338 if (mIsPrimaryTimerActive || mIsSecondaryTimerActive) { 339 if (DBG) log("Skip updating override network type since timer is active."); 340 return; 341 } 342 mOverrideNetworkType = getCurrentOverrideNetworkType(); 343 mDisplayInfoController.updateTelephonyDisplayInfo(); 344 } 345 getCurrentOverrideNetworkType()346 private @Annotation.OverrideNetworkType int getCurrentOverrideNetworkType() { 347 int displayNetworkType = TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE; 348 int dataNetworkType = mPhone.getServiceState().getDataNetworkType(); 349 // NR display is not accurate when physical channel config notifications are off 350 if (mIsPhysicalChannelConfigOn 351 && (mPhone.getServiceState().getNrState() != NetworkRegistrationInfo.NR_STATE_NONE 352 || dataNetworkType == TelephonyManager.NETWORK_TYPE_NR)) { 353 // Process NR display network type 354 displayNetworkType = getNrDisplayType(); 355 if (displayNetworkType == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE) { 356 // Use LTE values if 5G values aren't defined 357 displayNetworkType = getLteDisplayType(); 358 } 359 } else if (isLte(dataNetworkType)) { 360 // Process LTE display network type 361 displayNetworkType = getLteDisplayType(); 362 } 363 return displayNetworkType; 364 } 365 getNrDisplayType()366 private @Annotation.OverrideNetworkType int getNrDisplayType() { 367 // Don't show 5G icon if preferred network type does not include 5G 368 if ((RadioAccessFamily.getRafFromNetworkType(mPhone.getCachedPreferredNetworkType()) 369 & TelephonyManager.NETWORK_TYPE_BITMASK_NR) == 0) { 370 return TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE; 371 } 372 // Icon display keys in order of priority 373 List<String> keys = new ArrayList<>(); 374 // TODO: Update for NR SA 375 switch (mPhone.getServiceState().getNrState()) { 376 case NetworkRegistrationInfo.NR_STATE_CONNECTED: 377 if (isNrMmwave()) { 378 keys.add(STATE_CONNECTED_MMWAVE); 379 } 380 keys.add(STATE_CONNECTED); 381 break; 382 case NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED: 383 keys.add(isPhysicalLinkActive() ? STATE_NOT_RESTRICTED_RRC_CON 384 : STATE_NOT_RESTRICTED_RRC_IDLE); 385 break; 386 case NetworkRegistrationInfo.NR_STATE_RESTRICTED: 387 keys.add(STATE_RESTRICTED); 388 break; 389 } 390 391 for (String key : keys) { 392 OverrideTimerRule rule = mOverrideTimerRules.get(key); 393 if (rule != null && rule.mOverrideType 394 != TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE) { 395 return rule.mOverrideType; 396 } 397 } 398 return TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE; 399 } 400 getLteDisplayType()401 private @Annotation.OverrideNetworkType int getLteDisplayType() { 402 int value = TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE; 403 if (mPhone.getServiceState().getDataNetworkType() == TelephonyManager.NETWORK_TYPE_LTE_CA 404 || mPhone.getServiceState().isUsingCarrierAggregation()) { 405 value = TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_CA; 406 } 407 if (isLteEnhancedAvailable()) { 408 value = TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_ADVANCED_PRO; 409 } 410 return value; 411 } 412 isLteEnhancedAvailable()413 private boolean isLteEnhancedAvailable() { 414 if (TextUtils.isEmpty(mLteEnhancedPattern)) { 415 return false; 416 } 417 Pattern stringPattern = Pattern.compile(mLteEnhancedPattern); 418 for (String opName : new String[] {mPhone.getServiceState().getOperatorAlphaLongRaw(), 419 mPhone.getServiceState().getOperatorAlphaShortRaw()}) { 420 if (!TextUtils.isEmpty(opName)) { 421 Matcher matcher = stringPattern.matcher(opName); 422 if (matcher.find()) { 423 return true; 424 } 425 } 426 } 427 return false; 428 } 429 430 /** 431 * The parent state for all other states. 432 */ 433 private final class DefaultState extends State { 434 @Override processMessage(Message msg)435 public boolean processMessage(Message msg) { 436 if (DBG) log("DefaultState: process " + getEventName(msg.what)); 437 switch (msg.what) { 438 case EVENT_UPDATE: 439 resetAllTimers(); 440 transitionToCurrentState(); 441 break; 442 case EVENT_QUIT: 443 resetAllTimers(); 444 unRegisterForAllEvents(); 445 quit(); 446 break; 447 case EVENT_INITIALIZE: 448 // The reason that we do it here is because some of the works below requires 449 // other modules (e.g. DcTracker, ServiceStateTracker), which is not created 450 // yet when NetworkTypeController is created. 451 registerForAllEvents(); 452 parseCarrierConfigs(); 453 break; 454 case EVENT_DATA_RAT_CHANGED: 455 case EVENT_NR_STATE_CHANGED: 456 case EVENT_NR_FREQUENCY_CHANGED: 457 // ignored 458 break; 459 case EVENT_PHYSICAL_LINK_STATE_CHANGED: 460 AsyncResult ar = (AsyncResult) msg.obj; 461 mPhysicalLinkState = (int) ar.result; 462 break; 463 case EVENT_PHYSICAL_CHANNEL_CONFIG_NOTIF_CHANGED: 464 AsyncResult result = (AsyncResult) msg.obj; 465 mIsPhysicalChannelConfigOn = (boolean) result.result; 466 if (DBG) { 467 log("mIsPhysicalChannelConfigOn changed to: " + mIsPhysicalChannelConfigOn); 468 } 469 for (int event : ALL_EVENTS) { 470 removeMessages(event); 471 } 472 if (!mIsPhysicalChannelConfigOn) { 473 resetAllTimers(); 474 } 475 transitionToCurrentState(); 476 break; 477 case EVENT_CARRIER_CONFIG_CHANGED: 478 for (int event : ALL_EVENTS) { 479 removeMessages(event); 480 } 481 parseCarrierConfigs(); 482 resetAllTimers(); 483 transitionToCurrentState(); 484 break; 485 case EVENT_PRIMARY_TIMER_EXPIRED: 486 transitionWithSecondaryTimerTo((IState) msg.obj); 487 break; 488 case EVENT_SECONDARY_TIMER_EXPIRED: 489 mIsSecondaryTimerActive = false; 490 mSecondaryTimerState = ""; 491 updateTimers(); 492 updateOverrideNetworkType(); 493 break; 494 case EVENT_RADIO_OFF_OR_UNAVAILABLE: 495 resetAllTimers(); 496 transitionTo(mLegacyState); 497 break; 498 case EVENT_PREFERRED_NETWORK_MODE_CHANGED: 499 resetAllTimers(); 500 transitionToCurrentState(); 501 break; 502 default: 503 throw new RuntimeException("Received invalid event: " + msg.what); 504 } 505 return HANDLED; 506 } 507 } 508 509 private final DefaultState mDefaultState = new DefaultState(); 510 511 /** 512 * Device does not have NR available, due to any of the below reasons: 513 * <ul> 514 * <li> LTE cell does not support EN-DC 515 * <li> LTE cell supports EN-DC, but the use of NR is restricted 516 * <li> Data network type is not LTE, NR NSA, or NR SA 517 * </ul> 518 * This is the initial state. 519 */ 520 private final class LegacyState extends State { 521 private Boolean mIsNrRestricted = false; 522 523 @Override enter()524 public void enter() { 525 if (DBG) log("Entering LegacyState"); 526 updateTimers(); 527 updateOverrideNetworkType(); 528 if (!mIsPrimaryTimerActive && !mIsSecondaryTimerActive) { 529 mIsNrRestricted = isNrRestricted(); 530 mPreviousState = getName(); 531 } 532 } 533 534 @Override processMessage(Message msg)535 public boolean processMessage(Message msg) { 536 if (DBG) log("LegacyState: process " + getEventName(msg.what)); 537 updateTimers(); 538 int rat = mPhone.getServiceState().getDataNetworkType(); 539 switch (msg.what) { 540 case EVENT_DATA_RAT_CHANGED: 541 if (rat == TelephonyManager.NETWORK_TYPE_NR || isLte(rat) && isNrConnected()) { 542 transitionTo(mNrConnectedState); 543 } else if (isLte(rat) && isNrNotRestricted()) { 544 transitionWithTimerTo(isPhysicalLinkActive() 545 ? mLteConnectedState : mIdleState); 546 } else { 547 if (!isLte(rat)) { 548 // Rat is 3G or 2G, and it doesn't need NR timer. 549 resetAllTimers(); 550 } 551 updateOverrideNetworkType(); 552 } 553 mIsNrRestricted = isNrRestricted(); 554 break; 555 case EVENT_NR_STATE_CHANGED: 556 if (isNrConnected()) { 557 transitionTo(mNrConnectedState); 558 } else if (isLte(rat) && isNrNotRestricted()) { 559 transitionWithTimerTo(isPhysicalLinkActive() 560 ? mLteConnectedState : mIdleState); 561 } else if (isLte(rat) && isNrRestricted()) { 562 updateOverrideNetworkType(); 563 } 564 mIsNrRestricted = isNrRestricted(); 565 break; 566 case EVENT_NR_FREQUENCY_CHANGED: 567 // ignored 568 break; 569 case EVENT_PHYSICAL_LINK_STATE_CHANGED: 570 AsyncResult ar = (AsyncResult) msg.obj; 571 mPhysicalLinkState = (int) ar.result; 572 if (mIsTimerResetEnabledForLegacyStateRRCIdle && !isPhysicalLinkActive()) { 573 resetAllTimers(); 574 updateOverrideNetworkType(); 575 } 576 break; 577 default: 578 return NOT_HANDLED; 579 } 580 if (!mIsPrimaryTimerActive && !mIsSecondaryTimerActive) { 581 mPreviousState = getName(); 582 } 583 return HANDLED; 584 } 585 586 @Override getName()587 public String getName() { 588 return mIsNrRestricted ? STATE_RESTRICTED : STATE_LEGACY; 589 } 590 } 591 592 private final LegacyState mLegacyState = new LegacyState(); 593 594 /** 595 * Device does not have any physical connection with the cell (RRC idle). 596 */ 597 private final class IdleState extends State { 598 @Override enter()599 public void enter() { 600 if (DBG) log("Entering IdleState"); 601 updateTimers(); 602 updateOverrideNetworkType(); 603 if (!mIsPrimaryTimerActive && !mIsSecondaryTimerActive) { 604 mPreviousState = getName(); 605 } 606 } 607 608 @Override processMessage(Message msg)609 public boolean processMessage(Message msg) { 610 if (DBG) log("IdleState: process " + getEventName(msg.what)); 611 updateTimers(); 612 switch (msg.what) { 613 case EVENT_DATA_RAT_CHANGED: 614 int rat = mPhone.getServiceState().getDataNetworkType(); 615 if (rat == TelephonyManager.NETWORK_TYPE_NR) { 616 transitionTo(mNrConnectedState); 617 } else if (!isLte(rat) || !isNrNotRestricted()) { 618 transitionWithTimerTo(mLegacyState); 619 } 620 break; 621 case EVENT_NR_STATE_CHANGED: 622 if (isNrConnected()) { 623 transitionTo(mNrConnectedState); 624 } else if (!isNrNotRestricted()) { 625 transitionWithTimerTo(mLegacyState); 626 } 627 break; 628 case EVENT_NR_FREQUENCY_CHANGED: 629 // ignore 630 break; 631 case EVENT_PHYSICAL_LINK_STATE_CHANGED: 632 AsyncResult ar = (AsyncResult) msg.obj; 633 mPhysicalLinkState = (int) ar.result; 634 if (isNrNotRestricted()) { 635 // NOT_RESTRICTED_RRC_IDLE -> NOT_RESTRICTED_RRC_CON 636 if (isPhysicalLinkActive()) { 637 transitionWithTimerTo(mLteConnectedState); 638 } 639 } else { 640 log("NR state changed. Sending EVENT_NR_STATE_CHANGED"); 641 sendMessage(EVENT_NR_STATE_CHANGED); 642 } 643 break; 644 default: 645 return NOT_HANDLED; 646 } 647 if (!mIsPrimaryTimerActive && !mIsSecondaryTimerActive) { 648 mPreviousState = getName(); 649 } 650 return HANDLED; 651 } 652 653 @Override getName()654 public String getName() { 655 return STATE_NOT_RESTRICTED_RRC_IDLE; 656 } 657 } 658 659 private final IdleState mIdleState = new IdleState(); 660 661 /** 662 * Device is connected to LTE as the primary cell (RRC connected). 663 */ 664 private final class LteConnectedState extends State { 665 @Override enter()666 public void enter() { 667 if (DBG) log("Entering LteConnectedState"); 668 updateTimers(); 669 updateOverrideNetworkType(); 670 if (!mIsPrimaryTimerActive && !mIsSecondaryTimerActive) { 671 mPreviousState = getName(); 672 } 673 } 674 675 @Override processMessage(Message msg)676 public boolean processMessage(Message msg) { 677 if (DBG) log("LteConnectedState: process " + getEventName(msg.what)); 678 updateTimers(); 679 switch (msg.what) { 680 case EVENT_DATA_RAT_CHANGED: 681 int rat = mPhone.getServiceState().getDataNetworkType(); 682 if (rat == TelephonyManager.NETWORK_TYPE_NR) { 683 transitionTo(mNrConnectedState); 684 } else if (!isLte(rat) || !isNrNotRestricted()) { 685 transitionWithTimerTo(mLegacyState); 686 } 687 break; 688 case EVENT_NR_STATE_CHANGED: 689 if (isNrConnected()) { 690 transitionTo(mNrConnectedState); 691 } else if (!isNrNotRestricted()) { 692 transitionWithTimerTo(mLegacyState); 693 } 694 break; 695 case EVENT_NR_FREQUENCY_CHANGED: 696 // ignore 697 break; 698 case EVENT_PHYSICAL_LINK_STATE_CHANGED: 699 AsyncResult ar = (AsyncResult) msg.obj; 700 mPhysicalLinkState = (int) ar.result; 701 if (isNrNotRestricted()) { 702 // NOT_RESTRICTED_RRC_CON -> NOT_RESTRICTED_RRC_IDLE 703 if (!isPhysicalLinkActive()) { 704 transitionWithTimerTo(mIdleState); 705 } 706 } else { 707 log("NR state changed. Sending EVENT_NR_STATE_CHANGED"); 708 sendMessage(EVENT_NR_STATE_CHANGED); 709 } 710 break; 711 default: 712 return NOT_HANDLED; 713 } 714 if (!mIsPrimaryTimerActive && !mIsSecondaryTimerActive) { 715 mPreviousState = getName(); 716 } 717 return HANDLED; 718 } 719 720 @Override getName()721 public String getName() { 722 return STATE_NOT_RESTRICTED_RRC_CON; 723 } 724 } 725 726 private final LteConnectedState mLteConnectedState = new LteConnectedState(); 727 728 /** 729 * Device is connected to 5G NR as the secondary cell. 730 */ 731 private final class NrConnectedState extends State { 732 private Boolean mIsNrMmwave = false; 733 734 @Override enter()735 public void enter() { 736 if (DBG) log("Entering NrConnectedState"); 737 updateTimers(); 738 updateOverrideNetworkType(); 739 if (!mIsPrimaryTimerActive && !mIsSecondaryTimerActive) { 740 mIsNrMmwave = isNrMmwave(); 741 mPreviousState = getName(); 742 } 743 } 744 745 @Override processMessage(Message msg)746 public boolean processMessage(Message msg) { 747 if (DBG) log("NrConnectedState: process " + getEventName(msg.what)); 748 updateTimers(); 749 int rat = mPhone.getServiceState().getDataNetworkType(); 750 switch (msg.what) { 751 case EVENT_DATA_RAT_CHANGED: 752 if (rat == TelephonyManager.NETWORK_TYPE_NR || isLte(rat) && isNrConnected()) { 753 updateOverrideNetworkType(); 754 } else if (isLte(rat) && isNrNotRestricted()) { 755 transitionWithTimerTo(isPhysicalLinkActive() 756 ? mLteConnectedState : mIdleState); 757 } else { 758 transitionWithTimerTo(mLegacyState); 759 } 760 break; 761 case EVENT_NR_STATE_CHANGED: 762 if (isLte(rat) && isNrNotRestricted()) { 763 transitionWithTimerTo(isPhysicalLinkActive() 764 ? mLteConnectedState : mIdleState); 765 } else if (rat != TelephonyManager.NETWORK_TYPE_NR && !isNrConnected()) { 766 transitionWithTimerTo(mLegacyState); 767 } 768 break; 769 case EVENT_NR_FREQUENCY_CHANGED: 770 if (!isNrConnected()) { 771 log("NR state changed. Sending EVENT_NR_STATE_CHANGED"); 772 sendMessage(EVENT_NR_STATE_CHANGED); 773 break; 774 } 775 if (!isNrMmwave()) { 776 // STATE_CONNECTED_MMWAVE -> STATE_CONNECTED 777 transitionWithTimerTo(mNrConnectedState); 778 } else { 779 // STATE_CONNECTED -> STATE_CONNECTED_MMWAVE 780 transitionTo(mNrConnectedState); 781 } 782 mIsNrMmwave = isNrMmwave(); 783 break; 784 case EVENT_PHYSICAL_LINK_STATE_CHANGED: 785 AsyncResult ar = (AsyncResult) msg.obj; 786 mPhysicalLinkState = (int) ar.result; 787 if (!isNrConnected()) { 788 log("NR state changed. Sending EVENT_NR_STATE_CHANGED"); 789 sendMessage(EVENT_NR_STATE_CHANGED); 790 } 791 break; 792 default: 793 return NOT_HANDLED; 794 } 795 if (!mIsPrimaryTimerActive && !mIsSecondaryTimerActive) { 796 mPreviousState = getName(); 797 } 798 return HANDLED; 799 } 800 801 @Override getName()802 public String getName() { 803 return mIsNrMmwave ? STATE_CONNECTED_MMWAVE : STATE_CONNECTED; 804 } 805 } 806 807 private final NrConnectedState mNrConnectedState = new NrConnectedState(); 808 transitionWithTimerTo(IState destState)809 private void transitionWithTimerTo(IState destState) { 810 String destName = destState.getName(); 811 OverrideTimerRule rule = mOverrideTimerRules.get(mPreviousState); 812 if (rule != null && rule.getTimer(destName) > 0) { 813 if (DBG) log("Primary timer started for state: " + mPreviousState); 814 mPrimaryTimerState = mPreviousState; 815 mPreviousState = getCurrentState().getName(); 816 mIsPrimaryTimerActive = true; 817 sendMessageDelayed(EVENT_PRIMARY_TIMER_EXPIRED, destState, 818 rule.getTimer(destName) * 1000); 819 } 820 transitionTo(destState); 821 } 822 transitionWithSecondaryTimerTo(IState destState)823 private void transitionWithSecondaryTimerTo(IState destState) { 824 String currentName = getCurrentState().getName(); 825 OverrideTimerRule rule = mOverrideTimerRules.get(mPrimaryTimerState); 826 if (rule != null && rule.getSecondaryTimer(currentName) > 0) { 827 if (DBG) log("Secondary timer started for state: " + currentName); 828 mSecondaryTimerState = currentName; 829 mPreviousState = currentName; 830 mIsSecondaryTimerActive = true; 831 sendMessageDelayed(EVENT_SECONDARY_TIMER_EXPIRED, destState, 832 rule.getSecondaryTimer(currentName) * 1000); 833 } 834 mIsPrimaryTimerActive = false; 835 transitionTo(getCurrentState()); 836 } 837 transitionToCurrentState()838 private void transitionToCurrentState() { 839 int dataRat = mPhone.getServiceState().getDataNetworkType(); 840 IState transitionState; 841 if (dataRat == TelephonyManager.NETWORK_TYPE_NR || isNrConnected()) { 842 transitionState = mNrConnectedState; 843 mPreviousState = isNrMmwave() ? STATE_CONNECTED_MMWAVE : STATE_CONNECTED; 844 } else if (isLte(dataRat) && isNrNotRestricted()) { 845 if (isPhysicalLinkActive()) { 846 transitionState = mLteConnectedState; 847 mPreviousState = STATE_NOT_RESTRICTED_RRC_CON; 848 } else { 849 transitionState = mIdleState; 850 mPreviousState = STATE_NOT_RESTRICTED_RRC_IDLE; 851 } 852 } else { 853 transitionState = mLegacyState; 854 mPreviousState = isNrRestricted() ? STATE_RESTRICTED : STATE_LEGACY; 855 } 856 if (!transitionState.equals(getCurrentState())) { 857 transitionTo(transitionState); 858 } else { 859 updateOverrideNetworkType(); 860 } 861 } 862 updateTimers()863 private void updateTimers() { 864 String currentState = getCurrentState().getName(); 865 866 if (mIsPrimaryTimerActive && getOverrideNetworkType() == getCurrentOverrideNetworkType()) { 867 // remove primary timer if device goes back to the original icon 868 if (DBG) { 869 log("Remove primary timer since icon of primary state and current icon equal: " 870 + mPrimaryTimerState); 871 } 872 removeMessages(EVENT_PRIMARY_TIMER_EXPIRED); 873 mIsPrimaryTimerActive = false; 874 mPrimaryTimerState = ""; 875 } 876 877 if (mIsSecondaryTimerActive && !mSecondaryTimerState.equals(currentState)) { 878 // remove secondary timer if devices is no longer in secondary timer state 879 if (DBG) { 880 log("Remove secondary timer since current state (" + currentState 881 + ") is no longer secondary timer state (" + mSecondaryTimerState + ")."); 882 } 883 removeMessages(EVENT_SECONDARY_TIMER_EXPIRED); 884 mIsSecondaryTimerActive = false; 885 mSecondaryTimerState = ""; 886 } 887 888 if (currentState.equals(STATE_CONNECTED_MMWAVE)) { 889 resetAllTimers(); 890 } 891 892 int rat = mPhone.getServiceState().getDataNetworkType(); 893 if (!isLte(rat) && rat != TelephonyManager.NETWORK_TYPE_NR) { 894 // Rat is 3G or 2G, and it doesn't need NR timer. 895 resetAllTimers(); 896 } 897 } 898 resetAllTimers()899 private void resetAllTimers() { 900 if (DBG) { 901 log("Remove all timers"); 902 } 903 removeMessages(EVENT_PRIMARY_TIMER_EXPIRED); 904 removeMessages(EVENT_SECONDARY_TIMER_EXPIRED); 905 mIsPrimaryTimerActive = false; 906 mIsSecondaryTimerActive = false; 907 mPrimaryTimerState = ""; 908 mSecondaryTimerState = ""; 909 } 910 911 /** 912 * Private class defining timer rules between states to prevent flickering. These rules are 913 * created in {@link #parseCarrierConfigs()} based on various carrier configs. 914 */ 915 private class OverrideTimerRule { 916 /** The 5G state this timer rule applies for. See {@link #ALL_STATES}. */ 917 final String mState; 918 919 /** 920 * The override network type associated with this 5G state. This is the icon that will be 921 * displayed on the status bar. An override type of NONE will display the LTE value instead. 922 */ 923 final int mOverrideType; 924 925 /** 926 * A map of destination states and associated timers. If the 5G state changes from mState 927 * to the destination state, keep the override type until either the primary timer expires 928 * or mState is regained. 929 */ 930 final Map<String, Integer> mPrimaryTimers; 931 932 /** 933 * A map of secondary states and associated timers. After the primary timer expires, keep 934 * the override type until either the secondary timer expires or the device is no longer in 935 * the secondary state. 936 */ 937 final Map<String, Integer> mSecondaryTimers; 938 OverrideTimerRule(String state, int overrideType)939 OverrideTimerRule(String state, int overrideType) { 940 mState = state; 941 mOverrideType = overrideType; 942 mPrimaryTimers = new HashMap<>(); 943 mSecondaryTimers = new HashMap<>(); 944 } 945 946 /** 947 * Add a primary timer. 948 * @param destination Transitions from mState to the destination state. 949 * @param duration How long to keep the override type after transition to destination state. 950 */ addTimer(String destination, int duration)951 public void addTimer(String destination, int duration) { 952 mPrimaryTimers.put(destination, duration); 953 } 954 955 /** 956 * Add a secondary timer 957 * @param secondaryState Stays in secondaryState after primary timer expires. 958 * @param duration How long to keep the override type while in secondaryState. 959 */ addSecondaryTimer(String secondaryState, int duration)960 public void addSecondaryTimer(String secondaryState, int duration) { 961 mSecondaryTimers.put(secondaryState, duration); 962 } 963 964 /** 965 * @return Primary timer duration from mState to destination state, or 0 if not defined. 966 */ getTimer(String destination)967 public int getTimer(String destination) { 968 Integer timer = mPrimaryTimers.get(destination); 969 timer = timer == null ? mPrimaryTimers.get(STATE_ANY) : timer; 970 return timer == null ? 0 : timer; 971 } 972 973 /** 974 * @return Secondary timer duration for secondaryState, or 0 if not defined. 975 */ getSecondaryTimer(String secondaryState)976 public int getSecondaryTimer(String secondaryState) { 977 Integer secondaryTimer = mSecondaryTimers.get(secondaryState); 978 secondaryTimer = secondaryTimer == null 979 ? mSecondaryTimers.get(STATE_ANY) : secondaryTimer; 980 return secondaryTimer == null ? 0 : secondaryTimer; 981 } 982 983 @Override toString()984 public String toString() { 985 return "{mState=" + mState 986 + ", mOverrideType=" 987 + TelephonyDisplayInfo.overrideNetworkTypeToString(mOverrideType) 988 + ", mPrimaryTimers=" + mPrimaryTimers 989 + ", mSecondaryTimers=" + mSecondaryTimers + "}"; 990 } 991 } 992 isNrConnected()993 private boolean isNrConnected() { 994 return mPhone.getServiceState().getNrState() == NetworkRegistrationInfo.NR_STATE_CONNECTED; 995 } 996 isNrNotRestricted()997 private boolean isNrNotRestricted() { 998 return mPhone.getServiceState().getNrState() 999 == NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED; 1000 } 1001 isNrRestricted()1002 private boolean isNrRestricted() { 1003 return mPhone.getServiceState().getNrState() 1004 == NetworkRegistrationInfo.NR_STATE_RESTRICTED; 1005 } 1006 isNrMmwave()1007 private boolean isNrMmwave() { 1008 return mPhone.getServiceState().getNrFrequencyRange() 1009 == ServiceState.FREQUENCY_RANGE_MMWAVE; 1010 } 1011 isLte(int rat)1012 private boolean isLte(int rat) { 1013 return rat == TelephonyManager.NETWORK_TYPE_LTE 1014 || rat == TelephonyManager.NETWORK_TYPE_LTE_CA; 1015 } 1016 isPhysicalLinkActive()1017 private boolean isPhysicalLinkActive() { 1018 return mPhysicalLinkState == DcController.PHYSICAL_LINK_ACTIVE; 1019 } 1020 getEventName(int event)1021 private String getEventName(int event) { 1022 try { 1023 return sEvents[event]; 1024 } catch (ArrayIndexOutOfBoundsException e) { 1025 return "EVENT_NOT_DEFINED"; 1026 } 1027 } 1028 log(String s)1029 protected void log(String s) { 1030 Rlog.d(TAG, "[" + mPhone.getPhoneId() + "] " + s); 1031 } 1032 loge(String s)1033 protected void loge(String s) { 1034 Rlog.e(TAG, "[" + mPhone.getPhoneId() + "] " + s); 1035 } 1036 1037 @Override toString()1038 public String toString() { 1039 return "mOverrideTimerRules=" + mOverrideTimerRules.toString() 1040 + ", mLteEnhancedPattern=" + mLteEnhancedPattern 1041 + ", mIsPhysicalChannelConfigOn=" + mIsPhysicalChannelConfigOn 1042 + ", mIsPrimaryTimerActive=" + mIsPrimaryTimerActive 1043 + ", mIsSecondaryTimerActive=" + mIsSecondaryTimerActive 1044 + ", mPrimaryTimerState=" + mPrimaryTimerState 1045 + ", mSecondaryTimerState=" + mSecondaryTimerState 1046 + ", mPreviousState=" + mPreviousState; 1047 } 1048 1049 @Override dump(FileDescriptor fd, PrintWriter printWriter, String[] args)1050 public void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) { 1051 IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); 1052 pw.print("NetworkTypeController: "); 1053 super.dump(fd, pw, args); 1054 pw.flush(); 1055 pw.increaseIndent(); 1056 pw.println("mSubId=" + mPhone.getSubId()); 1057 pw.println("mOverrideTimerRules=" + mOverrideTimerRules.toString()); 1058 pw.println("mLteEnhancedPattern=" + mLteEnhancedPattern); 1059 pw.println("mIsPhysicalChannelConfigOn=" + mIsPhysicalChannelConfigOn); 1060 pw.println("mIsPrimaryTimerActive=" + mIsPrimaryTimerActive); 1061 pw.println("mIsSecondaryTimerActive=" + mIsSecondaryTimerActive); 1062 pw.println("mPrimaryTimerState=" + mPrimaryTimerState); 1063 pw.println("mSecondaryTimerState=" + mSecondaryTimerState); 1064 pw.println("mPreviousState=" + mPreviousState); 1065 pw.decreaseIndent(); 1066 pw.flush(); 1067 } 1068 } 1069