1 /* 2 * Copyright (C) 2019 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.cdnr; 18 19 import static com.android.internal.telephony.cdnr.EfData.EF_SOURCE_CARRIER_API; 20 import static com.android.internal.telephony.cdnr.EfData.EF_SOURCE_CARRIER_CONFIG; 21 import static com.android.internal.telephony.cdnr.EfData.EF_SOURCE_CSIM; 22 import static com.android.internal.telephony.cdnr.EfData.EF_SOURCE_DATA_OPERATOR_SIGNALLING; 23 import static com.android.internal.telephony.cdnr.EfData.EF_SOURCE_ERI; 24 import static com.android.internal.telephony.cdnr.EfData.EF_SOURCE_MODEM_CONFIG; 25 import static com.android.internal.telephony.cdnr.EfData.EF_SOURCE_RUIM; 26 import static com.android.internal.telephony.cdnr.EfData.EF_SOURCE_SIM; 27 import static com.android.internal.telephony.cdnr.EfData.EF_SOURCE_USIM; 28 import static com.android.internal.telephony.cdnr.EfData.EF_SOURCE_VOICE_OPERATOR_SIGNALLING; 29 30 import android.annotation.NonNull; 31 import android.content.Context; 32 import android.content.res.Configuration; 33 import android.content.res.Resources; 34 import android.os.PersistableBundle; 35 import android.telephony.CarrierConfigManager; 36 import android.telephony.ServiceState; 37 import android.telephony.SubscriptionManager; 38 import android.telephony.ims.stub.ImsRegistrationImplBase; 39 import android.text.TextUtils; 40 import android.util.LocalLog; 41 import android.util.SparseArray; 42 43 import com.android.internal.R; 44 import com.android.internal.telephony.GsmCdmaPhone; 45 import com.android.internal.telephony.Phone; 46 import com.android.internal.telephony.cdnr.EfData.EFSource; 47 import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppState; 48 import com.android.internal.telephony.uicc.IccRecords; 49 import com.android.internal.telephony.uicc.IccRecords.CarrierNameDisplayConditionBitmask; 50 import com.android.internal.telephony.uicc.IccRecords.OperatorPlmnInfo; 51 import com.android.internal.telephony.uicc.IccRecords.PlmnNetworkName; 52 import com.android.internal.telephony.uicc.RuimRecords; 53 import com.android.internal.telephony.uicc.SIMRecords; 54 import com.android.internal.util.IndentingPrintWriter; 55 import com.android.telephony.Rlog; 56 57 import java.util.Arrays; 58 import java.util.Collections; 59 import java.util.List; 60 import java.util.Locale; 61 import java.util.Objects; 62 63 /** Carrier display name resolver. */ 64 public class CarrierDisplayNameResolver { 65 private static final boolean DBG = true; 66 private static final String TAG = "CDNR"; 67 68 /** 69 * Only display SPN in home network, and PLMN network name in roaming network. 70 */ 71 @CarrierNameDisplayConditionBitmask 72 private static final int DEFAULT_CARRIER_NAME_DISPLAY_CONDITION_BITMASK = 0; 73 74 private static final CarrierDisplayNameConditionRule DEFAULT_CARRIER_DISPLAY_NAME_RULE = 75 new CarrierDisplayNameConditionRule(DEFAULT_CARRIER_NAME_DISPLAY_CONDITION_BITMASK); 76 77 private final SparseArray<EfData> mEf = new SparseArray<>(); 78 79 private final LocalLog mLocalLog; 80 private final Context mContext; 81 private final GsmCdmaPhone mPhone; 82 private final CarrierConfigManager mCCManager; 83 84 private CarrierDisplayNameData mCarrierDisplayNameData; 85 86 /** 87 * The priority of ef source. Lower index means higher priority. 88 */ 89 private static final List<Integer> EF_SOURCE_PRIORITY = 90 Arrays.asList( 91 EF_SOURCE_CARRIER_API, 92 EF_SOURCE_CARRIER_CONFIG, 93 EF_SOURCE_ERI, 94 EF_SOURCE_USIM, 95 EF_SOURCE_SIM, 96 EF_SOURCE_CSIM, 97 EF_SOURCE_RUIM, 98 EF_SOURCE_VOICE_OPERATOR_SIGNALLING, 99 EF_SOURCE_DATA_OPERATOR_SIGNALLING, 100 EF_SOURCE_MODEM_CONFIG); 101 CarrierDisplayNameResolver(GsmCdmaPhone phone)102 public CarrierDisplayNameResolver(GsmCdmaPhone phone) { 103 mLocalLog = new LocalLog(32); 104 mContext = phone.getContext(); 105 mPhone = phone; 106 mCCManager = (CarrierConfigManager) mContext.getSystemService( 107 Context.CARRIER_CONFIG_SERVICE); 108 } 109 110 /** 111 * Update the ef from Ruim. If {@code ruim} is null, the ef records from this source will be 112 * removed. 113 * 114 * @param ruim Ruim records. 115 */ updateEfFromRuim(RuimRecords ruim)116 public void updateEfFromRuim(RuimRecords ruim) { 117 int key = getSourcePriority(EF_SOURCE_RUIM); 118 if (ruim == null) { 119 mEf.remove(key); 120 } else { 121 mEf.put(key, new RuimEfData(ruim)); 122 } 123 } 124 125 /** 126 * Update the ef from Usim. If {@code usim} is null, the ef records from this source will be 127 * removed. 128 * 129 * @param usim Usim records. 130 */ updateEfFromUsim(SIMRecords usim)131 public void updateEfFromUsim(SIMRecords usim) { 132 int key = getSourcePriority(EF_SOURCE_USIM); 133 if (usim == null) { 134 mEf.remove(key); 135 } else { 136 mEf.put(key, new UsimEfData(usim)); 137 } 138 } 139 140 /** 141 * Update the ef from carrier config. If {@code config} is null, the ef records from this source 142 * will be removed. 143 * 144 * @param config carrier config. 145 */ updateEfFromCarrierConfig(PersistableBundle config)146 public void updateEfFromCarrierConfig(PersistableBundle config) { 147 int key = getSourcePriority(EF_SOURCE_CARRIER_CONFIG); 148 if (config == null) { 149 mEf.remove(key); 150 } else { 151 mEf.put(key, new CarrierConfigEfData(config)); 152 } 153 } 154 155 /** 156 * Update the ef for CDMA eri text. The ef records from this source will be set all of the 157 * following situation are satisfied. 158 * 159 * 1. {@code eriText} is neither empty nor null. 160 * 2. Current network is CDMA or CdmaLte 161 * 3. ERI is allowed. 162 * 163 * @param eriText 164 */ updateEfForEri(String eriText)165 public void updateEfForEri(String eriText) { 166 PersistableBundle config = getCarrierConfig(); 167 int key = getSourcePriority(EF_SOURCE_ERI); 168 if (!TextUtils.isEmpty(eriText) && (mPhone.isPhoneTypeCdma() || mPhone.isPhoneTypeCdmaLte()) 169 && config.getBoolean(CarrierConfigManager.KEY_ALLOW_ERI_BOOL)) { 170 mEf.put(key, new EriEfData(eriText)); 171 } else { 172 mEf.remove(key); 173 } 174 } 175 176 /** 177 * Update the ef for brandOverride. If {@code operatorName} is empty or null, the ef records 178 * from this source will be removed. 179 * 180 * @param operatorName operator name from brand override. 181 */ updateEfForBrandOverride(String operatorName)182 public void updateEfForBrandOverride(String operatorName) { 183 int key = getSourcePriority(EF_SOURCE_CARRIER_API); 184 if (TextUtils.isEmpty(operatorName)) { 185 mEf.remove(key); 186 } else { 187 mEf.put(key, 188 new BrandOverrideEfData(operatorName, getServiceState().getOperatorNumeric())); 189 } 190 } 191 192 /** Get the resolved carrier display name. */ getCarrierDisplayNameData()193 public CarrierDisplayNameData getCarrierDisplayNameData() { 194 resolveCarrierDisplayName(); 195 return mCarrierDisplayNameData; 196 } 197 198 @Override toString()199 public String toString() { 200 StringBuilder sb = new StringBuilder(); 201 for (int i = 0; i < mEf.size(); i++) { 202 EfData p = mEf.valueAt(i); 203 sb.append("{spnDisplayCondition = " 204 + p.getServiceProviderNameDisplayCondition(isRoaming()) 205 + ", spn = " + p.getServiceProviderName() 206 + ", spdiList = " + p.getServiceProviderDisplayInformation() 207 + ", pnnList = " + p.getPlmnNetworkNameList() 208 + ", oplList = " + p.getOperatorPlmnList() 209 + ", ehplmn = " + p.getEhplmnList() 210 + "}, "); 211 } 212 sb.append(", roamingFromSS = " + getServiceState().getRoaming()); 213 sb.append(", registeredPLMN = " + getServiceState().getOperatorNumeric()); 214 return sb.toString(); 215 } 216 217 /** 218 * Dumps information for carrier display name resolver. 219 * @param pw information printer. 220 */ dump(IndentingPrintWriter pw)221 public void dump(IndentingPrintWriter pw) { 222 pw.println("CDNR:"); 223 pw.increaseIndent(); 224 pw.println("fields = " + toString()); 225 pw.println("carrierDisplayNameData = " + mCarrierDisplayNameData); 226 pw.decreaseIndent(); 227 228 pw.println("CDNR local log:"); 229 pw.increaseIndent(); 230 mLocalLog.dump(pw); 231 pw.decreaseIndent(); 232 } 233 234 @NonNull getCarrierConfig()235 private PersistableBundle getCarrierConfig() { 236 PersistableBundle config = mCCManager.getConfigForSubId(mPhone.getSubId()); 237 if (config == null) config = CarrierConfigManager.getDefaultConfig(); 238 return config; 239 } 240 241 @NonNull getDisplayRule()242 private CarrierDisplayNameConditionRule getDisplayRule() { 243 boolean isRoaming = isRoaming(); 244 for (int i = 0; i < mEf.size(); i++) { 245 if (mEf.valueAt(i).getServiceProviderNameDisplayCondition(isRoaming) 246 != IccRecords.INVALID_CARRIER_NAME_DISPLAY_CONDITION_BITMASK) { 247 return new CarrierDisplayNameConditionRule( 248 mEf.valueAt(i).getServiceProviderNameDisplayCondition(isRoaming)); 249 } 250 } 251 return DEFAULT_CARRIER_DISPLAY_NAME_RULE; 252 } 253 254 @NonNull getEfSpdi()255 private List<String> getEfSpdi() { 256 for (int i = 0; i < mEf.size(); i++) { 257 if (mEf.valueAt(i).getServiceProviderDisplayInformation() != null) { 258 return mEf.valueAt(i).getServiceProviderDisplayInformation(); 259 } 260 } 261 return Collections.EMPTY_LIST; 262 } 263 264 @NonNull getEfSpn()265 private String getEfSpn() { 266 for (int i = 0; i < mEf.size(); i++) { 267 if (!TextUtils.isEmpty(mEf.valueAt(i).getServiceProviderName())) { 268 return mEf.valueAt(i).getServiceProviderName(); 269 } 270 } 271 return ""; 272 } 273 274 @NonNull getEfOpl()275 private List<OperatorPlmnInfo> getEfOpl() { 276 for (int i = 0; i < mEf.size(); i++) { 277 if (mEf.valueAt(i).getOperatorPlmnList() != null) { 278 return mEf.valueAt(i).getOperatorPlmnList(); 279 } 280 } 281 return Collections.EMPTY_LIST; 282 } 283 284 @NonNull getEfPnn()285 private List<PlmnNetworkName> getEfPnn() { 286 for (int i = 0; i < mEf.size(); i++) { 287 if (mEf.valueAt(i).getPlmnNetworkNameList() != null) { 288 return mEf.valueAt(i).getPlmnNetworkNameList(); 289 } 290 } 291 return Collections.EMPTY_LIST; 292 } 293 isRoaming()294 private boolean isRoaming() { 295 // Currently use the roaming state from ServiceState. 296 // EF_SPDI is only used when determine the service provider name and PLMN network name 297 // display condition rule. 298 // All the PLMNs will be considered HOME PLMNs if there is a brand override. 299 return getServiceState().getRoaming() 300 && !getEfSpdi().contains(getServiceState().getOperatorNumeric()); 301 } 302 getCarrierDisplayNameFromEf()303 private CarrierDisplayNameData getCarrierDisplayNameFromEf() { 304 CarrierDisplayNameConditionRule displayRule = getDisplayRule(); 305 306 String registeredPlmnName = getServiceState().getOperatorAlpha(); 307 String registeredPlmnNumeric = getServiceState().getOperatorNumeric(); 308 309 String spn = getEfSpn(); 310 311 // Resolve the PLMN network name 312 List<OperatorPlmnInfo> efOpl = getEfOpl(); 313 List<PlmnNetworkName> efPnn = getEfPnn(); 314 315 String plmn = null; 316 if (isRoaming()) { 317 plmn = registeredPlmnName; 318 } else { 319 if (efOpl.isEmpty()) { 320 // If the EF_OPL is not present, then the first record in EF_PNN is used for the 321 // default network name when registered in the HPLMN or an EHPLMN(if the EHPLMN 322 // list is present). 323 plmn = efPnn.isEmpty() ? "" : getPlmnNetworkName(efPnn.get(0)); 324 } else { 325 // TODO: Check the TAC/LAC & registered PLMN numeric in OPL list to determine which 326 // PLMN name should be used to override the current one. 327 } 328 } 329 330 // If no PLMN override is present, then the PLMN should be displayed: 331 // - operator alpha if it's not empty. 332 // - operator numeric. 333 if (TextUtils.isEmpty(plmn)) { 334 plmn = TextUtils.isEmpty(registeredPlmnName) ? registeredPlmnNumeric 335 : registeredPlmnName; 336 } 337 338 boolean showSpn = displayRule.shouldShowSpn(spn); 339 boolean showPlmn = TextUtils.isEmpty(spn) || displayRule.shouldShowPlmn(plmn); 340 341 return new CarrierDisplayNameData.Builder() 342 .setSpn(spn) 343 .setDataSpn(spn) 344 .setShowSpn(showSpn) 345 .setPlmn(plmn) 346 .setShowPlmn(showPlmn) 347 .build(); 348 } 349 getCarrierDisplayNameFromWifiCallingOverride( CarrierDisplayNameData rawCarrierDisplayNameData)350 private CarrierDisplayNameData getCarrierDisplayNameFromWifiCallingOverride( 351 CarrierDisplayNameData rawCarrierDisplayNameData) { 352 PersistableBundle config = getCarrierConfig(); 353 boolean useRootLocale = config.getBoolean(CarrierConfigManager.KEY_WFC_SPN_USE_ROOT_LOCALE); 354 Context displayNameContext = mContext; 355 if (useRootLocale) { 356 Configuration displayNameConfig = mContext.getResources().getConfiguration(); 357 displayNameConfig.setLocale(Locale.ROOT); 358 // Create a new Context for this temporary change 359 displayNameContext = mContext.createConfigurationContext(displayNameConfig); 360 } 361 Resources r = displayNameContext.getResources(); 362 String[] wfcSpnFormats = r.getStringArray(com.android.internal.R.array.wfcSpnFormats); 363 WfcCarrierNameFormatter wfcFormatter = new WfcCarrierNameFormatter(config, wfcSpnFormats, 364 getServiceState().getState() == ServiceState.STATE_POWER_OFF); 365 366 // Override the spn, data spn, plmn by wifi-calling 367 String wfcSpn = wfcFormatter.formatVoiceName(rawCarrierDisplayNameData.getSpn()); 368 String wfcDataSpn = wfcFormatter.formatDataName(rawCarrierDisplayNameData.getSpn()); 369 List<PlmnNetworkName> efPnn = getEfPnn(); 370 String plmn = efPnn.isEmpty() ? "" : getPlmnNetworkName(efPnn.get(0)); 371 String wfcPlmn = wfcFormatter.formatVoiceName( 372 TextUtils.isEmpty(plmn) ? rawCarrierDisplayNameData.getPlmn() : plmn); 373 374 CarrierDisplayNameData result = rawCarrierDisplayNameData; 375 if (!TextUtils.isEmpty(wfcSpn) && !TextUtils.isEmpty(wfcDataSpn)) { 376 result = new CarrierDisplayNameData.Builder() 377 .setSpn(wfcSpn) 378 .setDataSpn(wfcDataSpn) 379 .setShowSpn(true) 380 .build(); 381 } else if (!TextUtils.isEmpty(wfcPlmn)) { 382 result = new CarrierDisplayNameData.Builder() 383 .setPlmn(wfcPlmn) 384 .setShowPlmn(true) 385 .build(); 386 } 387 return result; 388 } 389 getCarrierDisplayNameFromCrossSimCallingOverride( CarrierDisplayNameData rawCarrierDisplayNameData)390 private CarrierDisplayNameData getCarrierDisplayNameFromCrossSimCallingOverride( 391 CarrierDisplayNameData rawCarrierDisplayNameData) { 392 PersistableBundle config = getCarrierConfig(); 393 int crossSimSpnFormatIdx = 394 config.getInt(CarrierConfigManager.KEY_CROSS_SIM_SPN_FORMAT_INT); 395 boolean useRootLocale = 396 config.getBoolean(CarrierConfigManager.KEY_WFC_SPN_USE_ROOT_LOCALE); 397 398 String[] crossSimSpnFormats = SubscriptionManager.getResourcesForSubId( 399 mPhone.getContext(), 400 mPhone.getSubId(), useRootLocale) 401 .getStringArray(R.array.crossSimSpnFormats); 402 403 if (crossSimSpnFormatIdx < 0 || crossSimSpnFormatIdx >= crossSimSpnFormats.length) { 404 Rlog.e(TAG, "updateSpnDisplay: KEY_CROSS_SIM_SPN_FORMAT_INT out of bounds: " 405 + crossSimSpnFormatIdx); 406 crossSimSpnFormatIdx = 0; 407 } 408 String crossSimSpnFormat = crossSimSpnFormats[crossSimSpnFormatIdx]; 409 // Override the spn, data spn, plmn by Cross-SIM Calling 410 List<PlmnNetworkName> efPnn = getEfPnn(); 411 String plmn = efPnn.isEmpty() ? "" : getPlmnNetworkName(efPnn.get(0)); 412 CarrierDisplayNameData result = rawCarrierDisplayNameData; 413 String rawSpn = rawCarrierDisplayNameData.getSpn(); 414 String rawPlmn = TextUtils.isEmpty(plmn) ? rawCarrierDisplayNameData.getPlmn() : plmn; 415 String crossSimSpn = String.format(crossSimSpnFormat, rawSpn); 416 String crossSimPlmn = String.format(crossSimSpnFormat, plmn); 417 if (!TextUtils.isEmpty(rawSpn) && !TextUtils.isEmpty(crossSimSpn)) { 418 result = new CarrierDisplayNameData.Builder() 419 .setSpn(crossSimSpn) 420 .setDataSpn(crossSimSpn) 421 .setShowSpn(true) 422 .build(); 423 } else if (!TextUtils.isEmpty(rawPlmn) && !TextUtils.isEmpty(crossSimPlmn)) { 424 result = new CarrierDisplayNameData.Builder() 425 .setPlmn(crossSimPlmn) 426 .setShowPlmn(true) 427 .build(); 428 } 429 return result; 430 } 431 432 /** 433 * Override the given carrier display name data {@code data} by out of service rule. 434 * @param data the carrier display name data need to be overridden. 435 * @return overridden carrier display name data. 436 */ getOutOfServiceDisplayName(CarrierDisplayNameData data)437 private CarrierDisplayNameData getOutOfServiceDisplayName(CarrierDisplayNameData data) { 438 // Out of service/Power off/Emergency Only override 439 // 1) In flight mode (service state is ServiceState.STATE_POWER_OFF). 440 // showPlmn = true 441 // Only show null as PLMN 442 // 443 // 2) Service state is ServiceState.STATE_OUT_OF_SERVICE but emergency call is not allowed. 444 // showPlmn = true 445 // Only show "No Service" as PLMN 446 // 447 // 3) Out of service but emergency call is allowed. 448 // showPlmn = true 449 // Only show "Emergency call only" as PLMN 450 String plmn = null; 451 boolean isSimReady = mPhone.getUiccCardApplication() != null 452 && mPhone.getUiccCardApplication().getState() == AppState.APPSTATE_READY; 453 boolean forceDisplayNoService = 454 mPhone.getServiceStateTracker().shouldForceDisplayNoService() && !isSimReady; 455 ServiceState ss = getServiceState(); 456 // The slot is emc only or oos but the device is emc only. 457 boolean isEmcOnly = ss.isEmergencyOnly() || Phone.isEmergencyCallOnly(); 458 if (ss.getState() == ServiceState.STATE_POWER_OFF && !forceDisplayNoService 459 && !isEmcOnly) { 460 plmn = null; 461 } else if (forceDisplayNoService || !isEmcOnly) { 462 plmn = mContext.getResources().getString( 463 com.android.internal.R.string.lockscreen_carrier_default); 464 } else { 465 plmn = mContext.getResources().getString( 466 com.android.internal.R.string.emergency_calls_only); 467 } 468 return new CarrierDisplayNameData.Builder() 469 .setSpn(data.getSpn()) 470 .setDataSpn(data.getDataSpn()) 471 .setShowSpn(data.shouldShowSpn()) 472 .setPlmn(plmn) 473 .setShowPlmn(true) 474 .build(); 475 } 476 resolveCarrierDisplayName()477 private void resolveCarrierDisplayName() { 478 CarrierDisplayNameData data = getCarrierDisplayNameFromEf(); 479 if (DBG) Rlog.d(TAG, "CarrierName from EF: " + data); 480 if ((mPhone.getImsPhone() != null) && (mPhone.getImsPhone().getImsRegistrationTech() 481 == ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM)) { 482 data = getCarrierDisplayNameFromCrossSimCallingOverride(data); 483 if (DBG) { 484 Rlog.d(TAG, "CarrierName override by Cross-SIM Calling " + data); 485 } 486 } else if (mPhone.getServiceStateTracker().getCombinedRegState(getServiceState()) 487 == ServiceState.STATE_IN_SERVICE) { 488 if (mPhone.isWifiCallingEnabled() && mPhone.isImsRegistered()) { 489 data = getCarrierDisplayNameFromWifiCallingOverride(data); 490 if (DBG) { 491 Rlog.d(TAG, "CarrierName override by wifi-calling " + data); 492 } 493 } else if (getServiceState().getState() == ServiceState.STATE_POWER_OFF) { 494 // data in service due to IWLAN but APM on and WFC not available 495 data = getOutOfServiceDisplayName(data); 496 if (DBG) Rlog.d(TAG, "Out of service carrierName (APM) " + data); 497 } 498 } else { 499 data = getOutOfServiceDisplayName(data); 500 if (DBG) Rlog.d(TAG, "Out of service carrierName " + data); 501 } 502 503 if (!Objects.equals(mCarrierDisplayNameData, data)) { 504 mLocalLog.log(String.format("ResolveCarrierDisplayName: %s", data.toString())); 505 } 506 507 mCarrierDisplayNameData = data; 508 } 509 510 /** 511 * Get the PLMN network name from the {@link PlmnNetworkName} object. 512 * @param name the {@link PlmnNetworkName} object may contain the full and short version of PLMN 513 * network name. 514 * @return full/short version PLMN network name if one of those is existed, otherwise return an 515 * empty string. 516 */ getPlmnNetworkName(PlmnNetworkName name)517 private static String getPlmnNetworkName(PlmnNetworkName name) { 518 if (name == null) return ""; 519 if (!TextUtils.isEmpty(name.fullName)) return name.fullName; 520 if (!TextUtils.isEmpty(name.shortName)) return name.shortName; 521 return ""; 522 } 523 524 /** 525 * Get the priority of the source of ef object. If {@code source} is not in the priority list, 526 * return {@link Integer#MAX_VALUE}. 527 * @param source source of ef object. 528 * @return the priority of the source of ef object. 529 */ getSourcePriority(@FSource int source)530 private static int getSourcePriority(@EFSource int source) { 531 int priority = EF_SOURCE_PRIORITY.indexOf(source); 532 if (priority == -1) priority = Integer.MAX_VALUE; 533 return priority; 534 } 535 536 private static final class CarrierDisplayNameConditionRule { 537 private int mDisplayConditionBitmask; 538 CarrierDisplayNameConditionRule(int carrierDisplayConditionBitmask)539 CarrierDisplayNameConditionRule(int carrierDisplayConditionBitmask) { 540 mDisplayConditionBitmask = carrierDisplayConditionBitmask; 541 } 542 shouldShowSpn(String spn)543 boolean shouldShowSpn(String spn) { 544 //Check if show SPN is required. 545 Boolean showSpn = ((mDisplayConditionBitmask 546 & IccRecords.CARRIER_NAME_DISPLAY_CONDITION_BITMASK_SPN) 547 == IccRecords.CARRIER_NAME_DISPLAY_CONDITION_BITMASK_SPN); 548 549 return !TextUtils.isEmpty(spn) && showSpn; 550 } 551 shouldShowPlmn(String plmn)552 boolean shouldShowPlmn(String plmn) { 553 // Check if show PLMN is required. 554 Boolean showPlmn = ((mDisplayConditionBitmask 555 & IccRecords.CARRIER_NAME_DISPLAY_CONDITION_BITMASK_PLMN) 556 == IccRecords.CARRIER_NAME_DISPLAY_CONDITION_BITMASK_PLMN); 557 558 return !TextUtils.isEmpty(plmn) && showPlmn; 559 } 560 561 @Override toString()562 public String toString() { 563 return String.format("{ SPN_bit = %d, PLMN_bit = %d }", 564 mDisplayConditionBitmask 565 & IccRecords.CARRIER_NAME_DISPLAY_CONDITION_BITMASK_SPN, 566 mDisplayConditionBitmask 567 & IccRecords.CARRIER_NAME_DISPLAY_CONDITION_BITMASK_PLMN); 568 } 569 } 570 getServiceState()571 private ServiceState getServiceState() { 572 return mPhone.getServiceStateTracker().getServiceState(); 573 } 574 575 /** 576 * WiFi-Calling formatter for carrier name. 577 */ 578 private static final class WfcCarrierNameFormatter { 579 final String mVoiceFormat; 580 final String mDataFormat; 581 WfcCarrierNameFormatter(@onNull PersistableBundle config, @NonNull String[] wfcFormats, boolean inFlightMode)582 WfcCarrierNameFormatter(@NonNull PersistableBundle config, 583 @NonNull String[] wfcFormats, boolean inFlightMode) { 584 int voiceIdx = config.getInt(CarrierConfigManager.KEY_WFC_SPN_FORMAT_IDX_INT); 585 int dataIdx = config.getInt(CarrierConfigManager.KEY_WFC_DATA_SPN_FORMAT_IDX_INT); 586 int flightModeIdx = config.getInt( 587 CarrierConfigManager.KEY_WFC_FLIGHT_MODE_SPN_FORMAT_IDX_INT); 588 589 if (voiceIdx < 0 || voiceIdx >= wfcFormats.length) { 590 Rlog.e(TAG, "updateSpnDisplay: KEY_WFC_SPN_FORMAT_IDX_INT out of bounds: " 591 + voiceIdx); 592 voiceIdx = 0; 593 } 594 595 if (dataIdx < 0 || dataIdx >= wfcFormats.length) { 596 Rlog.e(TAG, "updateSpnDisplay: KEY_WFC_DATA_SPN_FORMAT_IDX_INT out of bounds: " 597 + dataIdx); 598 dataIdx = 0; 599 } 600 601 if (flightModeIdx < 0 || flightModeIdx >= wfcFormats.length) { 602 // KEY_WFC_FLIGHT_MODE_SPN_FORMAT_IDX_INT out of bounds. Use the value from 603 // voiceIdx. 604 flightModeIdx = voiceIdx; 605 } 606 607 // flight mode 608 if (inFlightMode) { 609 voiceIdx = flightModeIdx; 610 } 611 612 mVoiceFormat = voiceIdx != -1 ? wfcFormats[voiceIdx] : ""; 613 mDataFormat = dataIdx != -1 ? wfcFormats[dataIdx] : ""; 614 } 615 616 /** 617 * Format the given {@code name} using wifi-calling voice name formatter. 618 * @param name the string need to be formatted. 619 * @return formatted string if {@code name} is not empty, otherwise return {@code name}. 620 */ formatVoiceName(String name)621 public String formatVoiceName(String name) { 622 if (TextUtils.isEmpty(name)) return name; 623 return String.format(mVoiceFormat, name.trim()); 624 } 625 626 /** 627 * Format the given {@code name} using wifi-calling data name formatter. 628 * @param name the string need to be formatted. 629 * @return formatted string if {@code name} is not empty, otherwise return {@code name}. 630 */ formatDataName(String name)631 public String formatDataName(String name) { 632 if (TextUtils.isEmpty(name)) return name; 633 return String.format(mDataFormat, name.trim()); 634 } 635 } 636 } 637