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 .setShowSpn(showSpn) 344 .setPlmn(plmn) 345 .setShowPlmn(showPlmn) 346 .build(); 347 } 348 getCarrierDisplayNameFromWifiCallingOverride( CarrierDisplayNameData rawCarrierDisplayNameData)349 private CarrierDisplayNameData getCarrierDisplayNameFromWifiCallingOverride( 350 CarrierDisplayNameData rawCarrierDisplayNameData) { 351 PersistableBundle config = getCarrierConfig(); 352 boolean useRootLocale = config.getBoolean(CarrierConfigManager.KEY_WFC_SPN_USE_ROOT_LOCALE); 353 Context displayNameContext = mContext; 354 if (useRootLocale) { 355 Configuration displayNameConfig = mContext.getResources().getConfiguration(); 356 displayNameConfig.setLocale(Locale.ROOT); 357 // Create a new Context for this temporary change 358 displayNameContext = mContext.createConfigurationContext(displayNameConfig); 359 } 360 Resources r = displayNameContext.getResources(); 361 String[] wfcSpnFormats = r.getStringArray(com.android.internal.R.array.wfcSpnFormats); 362 WfcCarrierNameFormatter wfcFormatter = new WfcCarrierNameFormatter(config, wfcSpnFormats, 363 getServiceState().getState() == ServiceState.STATE_POWER_OFF); 364 365 // Override the spn, data spn, plmn by wifi-calling 366 String wfcSpn = wfcFormatter.formatVoiceName(rawCarrierDisplayNameData.getSpn()); 367 String wfcDataSpn = wfcFormatter.formatDataName(rawCarrierDisplayNameData.getSpn()); 368 List<PlmnNetworkName> efPnn = getEfPnn(); 369 String plmn = efPnn.isEmpty() ? "" : getPlmnNetworkName(efPnn.get(0)); 370 String wfcPlmn = wfcFormatter.formatVoiceName( 371 TextUtils.isEmpty(plmn) ? rawCarrierDisplayNameData.getPlmn() : plmn); 372 373 CarrierDisplayNameData result = rawCarrierDisplayNameData; 374 if (!TextUtils.isEmpty(wfcSpn) && !TextUtils.isEmpty(wfcDataSpn)) { 375 result = new CarrierDisplayNameData.Builder() 376 .setSpn(wfcSpn) 377 .setDataSpn(wfcDataSpn) 378 .setShowSpn(true) 379 .build(); 380 } else if (!TextUtils.isEmpty(wfcPlmn)) { 381 result = new CarrierDisplayNameData.Builder() 382 .setPlmn(wfcPlmn) 383 .setShowPlmn(true) 384 .build(); 385 } 386 return result; 387 } 388 getCarrierDisplayNameFromCrossSimCallingOverride( CarrierDisplayNameData rawCarrierDisplayNameData)389 private CarrierDisplayNameData getCarrierDisplayNameFromCrossSimCallingOverride( 390 CarrierDisplayNameData rawCarrierDisplayNameData) { 391 PersistableBundle config = getCarrierConfig(); 392 int crossSimSpnFormatIdx = 393 config.getInt(CarrierConfigManager.KEY_CROSS_SIM_SPN_FORMAT_INT); 394 boolean useRootLocale = 395 config.getBoolean(CarrierConfigManager.KEY_WFC_SPN_USE_ROOT_LOCALE); 396 397 String[] crossSimSpnFormats = SubscriptionManager.getResourcesForSubId( 398 mPhone.getContext(), 399 mPhone.getSubId(), useRootLocale) 400 .getStringArray(R.array.crossSimSpnFormats); 401 402 if (crossSimSpnFormatIdx < 0 || crossSimSpnFormatIdx >= crossSimSpnFormats.length) { 403 Rlog.e(TAG, "updateSpnDisplay: KEY_CROSS_SIM_SPN_FORMAT_INT out of bounds: " 404 + crossSimSpnFormatIdx); 405 crossSimSpnFormatIdx = 0; 406 } 407 String crossSimSpnFormat = crossSimSpnFormats[crossSimSpnFormatIdx]; 408 // Override the spn, data spn, plmn by Cross-SIM Calling 409 List<PlmnNetworkName> efPnn = getEfPnn(); 410 String plmn = efPnn.isEmpty() ? "" : getPlmnNetworkName(efPnn.get(0)); 411 CarrierDisplayNameData result = rawCarrierDisplayNameData; 412 String rawSpn = rawCarrierDisplayNameData.getSpn(); 413 String rawPlmn = TextUtils.isEmpty(plmn) ? rawCarrierDisplayNameData.getPlmn() : plmn; 414 String crossSimSpn = String.format(crossSimSpnFormat, rawSpn); 415 String crossSimPlmn = String.format(crossSimSpnFormat, plmn); 416 if (!TextUtils.isEmpty(rawSpn) && !TextUtils.isEmpty(crossSimSpn)) { 417 result = new CarrierDisplayNameData.Builder() 418 .setSpn(crossSimSpn) 419 .setDataSpn(crossSimSpn) 420 .setShowSpn(true) 421 .build(); 422 } else if (!TextUtils.isEmpty(rawPlmn) && !TextUtils.isEmpty(crossSimPlmn)) { 423 result = new CarrierDisplayNameData.Builder() 424 .setPlmn(crossSimPlmn) 425 .setShowPlmn(true) 426 .build(); 427 } 428 return result; 429 } 430 431 /** 432 * Override the given carrier display name data {@code data} by out of service rule. 433 * @param data the carrier display name data need to be overridden. 434 * @return overridden carrier display name data. 435 */ getOutOfServiceDisplayName(CarrierDisplayNameData data)436 private CarrierDisplayNameData getOutOfServiceDisplayName(CarrierDisplayNameData data) { 437 // Out of service/Power off/Emergency Only override 438 // 1) In flight mode (service state is ServiceState.STATE_POWER_OFF). 439 // showPlmn = true 440 // Only show null as PLMN 441 // 442 // 2) Service state is ServiceState.STATE_OUT_OF_SERVICE but emergency call is not allowed. 443 // showPlmn = true 444 // Only show "No Service" as PLMN 445 // 446 // 3) Out of service but emergency call is allowed. 447 // showPlmn = true 448 // Only show "Emergency call only" as PLMN 449 String plmn = null; 450 boolean isSimReady = mPhone.getUiccCardApplication() != null 451 && mPhone.getUiccCardApplication().getState() == AppState.APPSTATE_READY; 452 boolean forceDisplayNoService = 453 mPhone.getServiceStateTracker().shouldForceDisplayNoService() && !isSimReady; 454 ServiceState ss = getServiceState(); 455 if (ss.getState() == ServiceState.STATE_POWER_OFF && !forceDisplayNoService 456 && !Phone.isEmergencyCallOnly()) { 457 plmn = null; 458 } else if (forceDisplayNoService || !Phone.isEmergencyCallOnly()) { 459 plmn = mContext.getResources().getString( 460 com.android.internal.R.string.lockscreen_carrier_default); 461 } else { 462 plmn = mContext.getResources().getString( 463 com.android.internal.R.string.emergency_calls_only); 464 } 465 return new CarrierDisplayNameData.Builder() 466 .setSpn(data.getSpn()) 467 .setDataSpn(data.getDataSpn()) 468 .setShowSpn(data.shouldShowSpn()) 469 .setPlmn(plmn) 470 .setShowPlmn(true) 471 .build(); 472 } 473 resolveCarrierDisplayName()474 private void resolveCarrierDisplayName() { 475 CarrierDisplayNameData data = getCarrierDisplayNameFromEf(); 476 if (DBG) Rlog.d(TAG, "CarrierName from EF: " + data); 477 if ((mPhone.getImsPhone() != null) && (mPhone.getImsPhone().getImsRegistrationTech() 478 == ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM)) { 479 data = getCarrierDisplayNameFromCrossSimCallingOverride(data); 480 if (DBG) { 481 Rlog.d(TAG, "CarrierName override by Cross-SIM Calling " + data); 482 } 483 } else if (mPhone.getServiceStateTracker().getCombinedRegState(getServiceState()) 484 == ServiceState.STATE_IN_SERVICE) { 485 if (mPhone.isWifiCallingEnabled()) { 486 data = getCarrierDisplayNameFromWifiCallingOverride(data); 487 if (DBG) { 488 Rlog.d(TAG, "CarrierName override by wifi-calling " + data); 489 } 490 } else if (getServiceState().getState() == ServiceState.STATE_POWER_OFF) { 491 // data in service due to IWLAN but APM on and WFC not available 492 data = getOutOfServiceDisplayName(data); 493 if (DBG) Rlog.d(TAG, "Out of service carrierName (APM) " + data); 494 } 495 } else { 496 data = getOutOfServiceDisplayName(data); 497 if (DBG) Rlog.d(TAG, "Out of service carrierName " + data); 498 } 499 500 if (!Objects.equals(mCarrierDisplayNameData, data)) { 501 mLocalLog.log(String.format("ResolveCarrierDisplayName: %s", data.toString())); 502 } 503 504 mCarrierDisplayNameData = data; 505 } 506 507 /** 508 * Get the PLMN network name from the {@link PlmnNetworkName} object. 509 * @param name the {@link PlmnNetworkName} object may contain the full and short version of PLMN 510 * network name. 511 * @return full/short version PLMN network name if one of those is existed, otherwise return an 512 * empty string. 513 */ getPlmnNetworkName(PlmnNetworkName name)514 private static String getPlmnNetworkName(PlmnNetworkName name) { 515 if (name == null) return ""; 516 if (!TextUtils.isEmpty(name.fullName)) return name.fullName; 517 if (!TextUtils.isEmpty(name.shortName)) return name.shortName; 518 return ""; 519 } 520 521 /** 522 * Get the priority of the source of ef object. If {@code source} is not in the priority list, 523 * return {@link Integer#MAX_VALUE}. 524 * @param source source of ef object. 525 * @return the priority of the source of ef object. 526 */ getSourcePriority(@FSource int source)527 private static int getSourcePriority(@EFSource int source) { 528 int priority = EF_SOURCE_PRIORITY.indexOf(source); 529 if (priority == -1) priority = Integer.MAX_VALUE; 530 return priority; 531 } 532 533 private static final class CarrierDisplayNameConditionRule { 534 private int mDisplayConditionBitmask; 535 CarrierDisplayNameConditionRule(int carrierDisplayConditionBitmask)536 CarrierDisplayNameConditionRule(int carrierDisplayConditionBitmask) { 537 mDisplayConditionBitmask = carrierDisplayConditionBitmask; 538 } 539 shouldShowSpn(String spn)540 boolean shouldShowSpn(String spn) { 541 //Check if show SPN is required. 542 Boolean showSpn = ((mDisplayConditionBitmask 543 & IccRecords.CARRIER_NAME_DISPLAY_CONDITION_BITMASK_SPN) 544 == IccRecords.CARRIER_NAME_DISPLAY_CONDITION_BITMASK_SPN); 545 546 return !TextUtils.isEmpty(spn) && showSpn; 547 } 548 shouldShowPlmn(String plmn)549 boolean shouldShowPlmn(String plmn) { 550 // Check if show PLMN is required. 551 Boolean showPlmn = ((mDisplayConditionBitmask 552 & IccRecords.CARRIER_NAME_DISPLAY_CONDITION_BITMASK_PLMN) 553 == IccRecords.CARRIER_NAME_DISPLAY_CONDITION_BITMASK_PLMN); 554 555 return !TextUtils.isEmpty(plmn) && showPlmn; 556 } 557 558 @Override toString()559 public String toString() { 560 return String.format("{ SPN_bit = %d, PLMN_bit = %d }", 561 mDisplayConditionBitmask 562 & IccRecords.CARRIER_NAME_DISPLAY_CONDITION_BITMASK_SPN, 563 mDisplayConditionBitmask 564 & IccRecords.CARRIER_NAME_DISPLAY_CONDITION_BITMASK_PLMN); 565 } 566 } 567 getServiceState()568 private ServiceState getServiceState() { 569 return mPhone.getServiceStateTracker().getServiceState(); 570 } 571 572 /** 573 * WiFi-Calling formatter for carrier name. 574 */ 575 private static final class WfcCarrierNameFormatter { 576 final String mVoiceFormat; 577 final String mDataFormat; 578 WfcCarrierNameFormatter(@onNull PersistableBundle config, @NonNull String[] wfcFormats, boolean inFlightMode)579 WfcCarrierNameFormatter(@NonNull PersistableBundle config, 580 @NonNull String[] wfcFormats, boolean inFlightMode) { 581 int voiceIdx = config.getInt(CarrierConfigManager.KEY_WFC_SPN_FORMAT_IDX_INT); 582 int dataIdx = config.getInt(CarrierConfigManager.KEY_WFC_DATA_SPN_FORMAT_IDX_INT); 583 int flightModeIdx = config.getInt( 584 CarrierConfigManager.KEY_WFC_FLIGHT_MODE_SPN_FORMAT_IDX_INT); 585 586 if (voiceIdx < 0 || voiceIdx >= wfcFormats.length) { 587 Rlog.e(TAG, "updateSpnDisplay: KEY_WFC_SPN_FORMAT_IDX_INT out of bounds: " 588 + voiceIdx); 589 voiceIdx = 0; 590 } 591 592 if (dataIdx < 0 || dataIdx >= wfcFormats.length) { 593 Rlog.e(TAG, "updateSpnDisplay: KEY_WFC_DATA_SPN_FORMAT_IDX_INT out of bounds: " 594 + dataIdx); 595 dataIdx = 0; 596 } 597 598 if (flightModeIdx < 0 || flightModeIdx >= wfcFormats.length) { 599 // KEY_WFC_FLIGHT_MODE_SPN_FORMAT_IDX_INT out of bounds. Use the value from 600 // voiceIdx. 601 flightModeIdx = voiceIdx; 602 } 603 604 // flight mode 605 if (inFlightMode) { 606 voiceIdx = flightModeIdx; 607 } 608 609 mVoiceFormat = voiceIdx != -1 ? wfcFormats[voiceIdx] : ""; 610 mDataFormat = dataIdx != -1 ? wfcFormats[dataIdx] : ""; 611 } 612 613 /** 614 * Format the given {@code name} using wifi-calling voice name formatter. 615 * @param name the string need to be formatted. 616 * @return formatted string if {@code name} is not empty, otherwise return {@code name}. 617 */ formatVoiceName(String name)618 public String formatVoiceName(String name) { 619 if (TextUtils.isEmpty(name)) return name; 620 return String.format(mVoiceFormat, name.trim()); 621 } 622 623 /** 624 * Format the given {@code name} using wifi-calling data name formatter. 625 * @param name the string need to be formatted. 626 * @return formatted string if {@code name} is not empty, otherwise return {@code name}. 627 */ formatDataName(String name)628 public String formatDataName(String name) { 629 if (TextUtils.isEmpty(name)) return name; 630 return String.format(mDataFormat, name.trim()); 631 } 632 } 633 } 634