1 package org.robolectric.shadows; 2 3 import static android.os.Build.VERSION_CODES.LOLLIPOP_MR1; 4 import static android.os.Build.VERSION_CODES.M; 5 import static android.os.Build.VERSION_CODES.N; 6 import static android.os.Build.VERSION_CODES.O_MR1; 7 import static android.os.Build.VERSION_CODES.P; 8 import static android.os.Build.VERSION_CODES.Q; 9 import static android.os.Build.VERSION_CODES.R; 10 import static android.os.Build.VERSION_CODES.TIRAMISU; 11 12 import android.os.Build.VERSION; 13 import android.telephony.SubscriptionInfo; 14 import android.telephony.SubscriptionManager; 15 import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; 16 import com.google.common.collect.ImmutableList; 17 import java.util.ArrayList; 18 import java.util.Arrays; 19 import java.util.HashMap; 20 import java.util.HashSet; 21 import java.util.List; 22 import java.util.Map; 23 import java.util.Set; 24 import java.util.concurrent.Executor; 25 import org.robolectric.annotation.HiddenApi; 26 import org.robolectric.annotation.Implementation; 27 import org.robolectric.annotation.Implements; 28 import org.robolectric.annotation.Resetter; 29 import org.robolectric.util.ReflectionHelpers; 30 31 @Implements(value = SubscriptionManager.class, minSdk = LOLLIPOP_MR1) 32 public class ShadowSubscriptionManager { 33 34 private boolean readPhoneStatePermission = true; 35 private boolean readPhoneNumbersPermission = true; 36 public static final int INVALID_PHONE_INDEX = 37 ReflectionHelpers.getStaticField(SubscriptionManager.class, "INVALID_PHONE_INDEX"); 38 39 private static int activeDataSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; 40 private static int defaultSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; 41 private static int defaultDataSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; 42 private static int defaultSmsSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; 43 private static int defaultVoiceSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; 44 45 private final Map<Integer, String> phoneNumberMap = new HashMap<>(); 46 47 /** Returns value set with {@link #setActiveDataSubscriptionId(int)}. */ 48 @Implementation(minSdk = R) getActiveDataSubscriptionId()49 protected static int getActiveDataSubscriptionId() { 50 return activeDataSubscriptionId; 51 } 52 53 /** Returns value set with {@link #setDefaultSubscriptionId(int)}. */ 54 @Implementation(minSdk = N) getDefaultSubscriptionId()55 protected static int getDefaultSubscriptionId() { 56 return defaultSubscriptionId; 57 } 58 59 /** Returns value set with {@link #setDefaultDataSubscriptionId(int)}. */ 60 @Implementation(minSdk = N) getDefaultDataSubscriptionId()61 protected static int getDefaultDataSubscriptionId() { 62 return defaultDataSubscriptionId; 63 } 64 65 /** Returns value set with {@link #setDefaultSmsSubscriptionId(int)}. */ 66 @Implementation(minSdk = N) getDefaultSmsSubscriptionId()67 protected static int getDefaultSmsSubscriptionId() { 68 return defaultSmsSubscriptionId; 69 } 70 71 /** Returns value set with {@link #setDefaultVoiceSubscriptionId(int)}. */ 72 @Implementation(minSdk = N) getDefaultVoiceSubscriptionId()73 protected static int getDefaultVoiceSubscriptionId() { 74 return defaultVoiceSubscriptionId; 75 } 76 77 @Implementation(maxSdk = M) 78 @HiddenApi getDefaultSubId()79 protected static int getDefaultSubId() { 80 return defaultSubscriptionId; 81 } 82 83 @Implementation(maxSdk = M) 84 @HiddenApi getDefaultVoiceSubId()85 protected static int getDefaultVoiceSubId() { 86 return defaultVoiceSubscriptionId; 87 } 88 89 @Implementation(maxSdk = M) 90 @HiddenApi getDefaultSmsSubId()91 protected static int getDefaultSmsSubId() { 92 return defaultSmsSubscriptionId; 93 } 94 95 @Implementation(maxSdk = M) 96 @HiddenApi getDefaultDataSubId()97 protected static int getDefaultDataSubId() { 98 return defaultDataSubscriptionId; 99 } 100 101 /** Sets the value that will be returned by {@link #getActiveDataSubscriptionId()}. */ setActiveDataSubscriptionId(int activeDataSubscriptionId)102 public static void setActiveDataSubscriptionId(int activeDataSubscriptionId) { 103 ShadowSubscriptionManager.activeDataSubscriptionId = activeDataSubscriptionId; 104 } 105 106 /** Sets the value that will be returned by {@link #getDefaultSubscriptionId()}. */ setDefaultSubscriptionId(int defaultSubscriptionId)107 public static void setDefaultSubscriptionId(int defaultSubscriptionId) { 108 ShadowSubscriptionManager.defaultSubscriptionId = defaultSubscriptionId; 109 } 110 setDefaultDataSubscriptionId(int defaultDataSubscriptionId)111 public static void setDefaultDataSubscriptionId(int defaultDataSubscriptionId) { 112 ShadowSubscriptionManager.defaultDataSubscriptionId = defaultDataSubscriptionId; 113 } 114 setDefaultSmsSubscriptionId(int defaultSmsSubscriptionId)115 public static void setDefaultSmsSubscriptionId(int defaultSmsSubscriptionId) { 116 ShadowSubscriptionManager.defaultSmsSubscriptionId = defaultSmsSubscriptionId; 117 } 118 setDefaultVoiceSubscriptionId(int defaultVoiceSubscriptionId)119 public static void setDefaultVoiceSubscriptionId(int defaultVoiceSubscriptionId) { 120 ShadowSubscriptionManager.defaultVoiceSubscriptionId = defaultVoiceSubscriptionId; 121 } 122 123 /** 124 * Cache of phone IDs used by {@link getPhoneId}. Managed by {@link putPhoneId} and {@link 125 * removePhoneId}. 126 */ 127 private static Map<Integer, Integer> phoneIds = new HashMap<>(); 128 129 /** 130 * Cache of {@link SubscriptionInfo} used by {@link #getActiveSubscriptionInfoList}. Managed by 131 * {@link #setActiveSubscriptionInfoList}. 132 */ 133 private List<SubscriptionInfo> subscriptionList = new ArrayList<>(); 134 /** 135 * Cache of {@link SubscriptionInfo} used by {@link #getAvailableSubscriptionInfoList}. Managed by 136 * {@link #setAvailableSubscriptionInfos}. 137 */ 138 private List<SubscriptionInfo> availableSubscriptionList = new ArrayList<>(); 139 /** 140 * List of listeners to be notified if the list of {@link SubscriptionInfo} changes. Managed by 141 * {@link #addOnSubscriptionsChangedListener} and {@link removeOnSubscriptionsChangedListener}. 142 */ 143 private List<OnSubscriptionsChangedListener> listeners = new ArrayList<>(); 144 /** 145 * Cache of subscription ids used by {@link #isNetworkRoaming}. Managed by {@link 146 * #setNetworkRoamingStatus} and {@link #clearNetworkRoamingStatus}. 147 */ 148 private Set<Integer> roamingSimSubscriptionIds = new HashSet<>(); 149 150 /** 151 * Returns the active list of {@link SubscriptionInfo} that were set via {@link 152 * #setActiveSubscriptionInfoList}. 153 */ 154 @Implementation(minSdk = LOLLIPOP_MR1) getActiveSubscriptionInfoList()155 protected List<SubscriptionInfo> getActiveSubscriptionInfoList() { 156 checkReadPhoneStatePermission(); 157 return subscriptionList; 158 } 159 160 /** 161 * Returns the available list of {@link SubscriptionInfo} that were set via {@link 162 * #setAvailableSubscriptionInfoList}. 163 */ 164 @Implementation(minSdk = O_MR1) getAvailableSubscriptionInfoList()165 protected List<SubscriptionInfo> getAvailableSubscriptionInfoList() { 166 return availableSubscriptionList; 167 } 168 169 /** 170 * Returns the size of the list of {@link SubscriptionInfo} that were set via {@link 171 * #setActiveSubscriptionInfoList}. If no list was set, returns 0. 172 */ 173 @Implementation(minSdk = LOLLIPOP_MR1) getActiveSubscriptionInfoCount()174 protected int getActiveSubscriptionInfoCount() { 175 checkReadPhoneStatePermission(); 176 return subscriptionList == null ? 0 : subscriptionList.size(); 177 } 178 179 /** 180 * Returns subscription that were set via {@link #setActiveSubscriptionInfoList} if it can find 181 * one with the specified id or null if none found. 182 * 183 * <p>An exception will be thrown if the READ_PHONE_STATE permission has not been granted. 184 */ 185 @Implementation(minSdk = LOLLIPOP_MR1) getActiveSubscriptionInfo(int subId)186 protected SubscriptionInfo getActiveSubscriptionInfo(int subId) { 187 checkReadPhoneStatePermission(); 188 if (subscriptionList == null) { 189 return null; 190 } 191 for (SubscriptionInfo info : subscriptionList) { 192 if (info.getSubscriptionId() == subId) { 193 return info; 194 } 195 } 196 return null; 197 } 198 199 /** 200 * @return the maximum number of active subscriptions that will be returned by {@link 201 * #getActiveSubscriptionInfoList} and the value returned by {@link 202 * #getActiveSubscriptionInfoCount}. 203 */ 204 @Implementation(minSdk = LOLLIPOP_MR1) getActiveSubscriptionInfoCountMax()205 protected int getActiveSubscriptionInfoCountMax() { 206 List<SubscriptionInfo> infoList = getActiveSubscriptionInfoList(); 207 208 if (infoList == null) { 209 return getActiveSubscriptionInfoCount(); 210 } 211 212 return Math.max(getActiveSubscriptionInfoList().size(), getActiveSubscriptionInfoCount()); 213 } 214 215 /** 216 * Returns subscription that were set via {@link #setActiveSubscriptionInfoList} if it can find 217 * one with the specified slot index or null if none found. 218 */ 219 @Implementation(minSdk = N) getActiveSubscriptionInfoForSimSlotIndex(int slotIndex)220 protected SubscriptionInfo getActiveSubscriptionInfoForSimSlotIndex(int slotIndex) { 221 checkReadPhoneStatePermission(); 222 if (subscriptionList == null) { 223 return null; 224 } 225 for (SubscriptionInfo info : subscriptionList) { 226 if (info.getSimSlotIndex() == slotIndex) { 227 return info; 228 } 229 } 230 return null; 231 } 232 233 /** 234 * Sets the active list of {@link SubscriptionInfo}. This call internally triggers {@link 235 * OnSubscriptionsChangedListener#onSubscriptionsChanged()} to all the listeners. 236 * 237 * @param list - The subscription info list, can be null. 238 */ setActiveSubscriptionInfoList(List<SubscriptionInfo> list)239 public void setActiveSubscriptionInfoList(List<SubscriptionInfo> list) { 240 subscriptionList = list; 241 dispatchOnSubscriptionsChanged(); 242 } 243 244 /** 245 * Sets the active list of {@link SubscriptionInfo}. This call internally triggers {@link 246 * OnSubscriptionsChangedListener#onSubscriptionsChanged()} to all the listeners. 247 * 248 * @param list - The subscription info list, can be null. 249 */ setAvailableSubscriptionInfoList(List<SubscriptionInfo> list)250 public void setAvailableSubscriptionInfoList(List<SubscriptionInfo> list) { 251 availableSubscriptionList = list; 252 dispatchOnSubscriptionsChanged(); 253 } 254 255 /** 256 * Sets the active list of {@link SubscriptionInfo}. This call internally triggers {@link 257 * OnSubscriptionsChangedListener#onSubscriptionsChanged()} to all the listeners. 258 */ setActiveSubscriptionInfos(SubscriptionInfo... infos)259 public void setActiveSubscriptionInfos(SubscriptionInfo... infos) { 260 if (infos == null) { 261 setActiveSubscriptionInfoList(ImmutableList.of()); 262 } else { 263 setActiveSubscriptionInfoList(Arrays.asList(infos)); 264 } 265 } 266 267 /** 268 * Sets the active list of {@link SubscriptionInfo}. This call internally triggers {@link 269 * OnSubscriptionsChangedListener#onSubscriptionsChanged()} to all the listeners. 270 */ setAvailableSubscriptionInfos(SubscriptionInfo... infos)271 public void setAvailableSubscriptionInfos(SubscriptionInfo... infos) { 272 if (infos == null) { 273 setAvailableSubscriptionInfoList(ImmutableList.of()); 274 } else { 275 setAvailableSubscriptionInfoList(Arrays.asList(infos)); 276 } 277 } 278 279 /** 280 * Adds a listener to a local list of listeners. Will be triggered by {@link 281 * #setActiveSubscriptionInfoList} when the local list of {@link SubscriptionInfo} is updated. 282 */ 283 @Implementation(minSdk = LOLLIPOP_MR1) addOnSubscriptionsChangedListener(OnSubscriptionsChangedListener listener)284 protected void addOnSubscriptionsChangedListener(OnSubscriptionsChangedListener listener) { 285 listeners.add(listener); 286 listener.onSubscriptionsChanged(); 287 } 288 289 /** 290 * Adds a listener to a local list of listeners. Will be triggered by {@link 291 * #setActiveSubscriptionInfoList} when the local list of {@link SubscriptionInfo} is updated. 292 */ 293 @Implementation(minSdk = R) addOnSubscriptionsChangedListener( Executor executor, OnSubscriptionsChangedListener listener)294 protected void addOnSubscriptionsChangedListener( 295 Executor executor, OnSubscriptionsChangedListener listener) { 296 listeners.add(listener); 297 listener.onSubscriptionsChanged(); 298 } 299 300 /** 301 * Removes a listener from a local list of listeners. Will be triggered by {@link 302 * #setActiveSubscriptionInfoList} when the local list of {@link SubscriptionInfo} is updated. 303 */ 304 @Implementation(minSdk = LOLLIPOP_MR1) removeOnSubscriptionsChangedListener(OnSubscriptionsChangedListener listener)305 protected void removeOnSubscriptionsChangedListener(OnSubscriptionsChangedListener listener) { 306 listeners.remove(listener); 307 } 308 309 /** 310 * Check if a listener exists in the {@link ShadowSubscriptionManager.listeners}. 311 * 312 * @param listener The listener to check. 313 * @return boolean True if the listener already added, otherwise false. 314 */ hasOnSubscriptionsChangedListener(OnSubscriptionsChangedListener listener)315 public boolean hasOnSubscriptionsChangedListener(OnSubscriptionsChangedListener listener) { 316 return listeners.contains(listener); 317 } 318 319 /** Returns subscription Ids that were set via {@link #setActiveSubscriptionInfoList}. */ 320 @Implementation(minSdk = LOLLIPOP_MR1) 321 @HiddenApi getActiveSubscriptionIdList()322 protected int[] getActiveSubscriptionIdList() { 323 final List<SubscriptionInfo> infos = getActiveSubscriptionInfoList(); 324 if (infos == null) { 325 return new int[0]; 326 } 327 int[] ids = new int[infos.size()]; 328 for (int i = 0; i < infos.size(); i++) { 329 ids[i] = infos.get(i).getSubscriptionId(); 330 } 331 return ids; 332 } 333 334 /** 335 * Notifies {@link OnSubscriptionsChangedListener} listeners that the list of {@link 336 * SubscriptionInfo} has been updated. 337 */ dispatchOnSubscriptionsChanged()338 private void dispatchOnSubscriptionsChanged() { 339 for (OnSubscriptionsChangedListener listener : listeners) { 340 listener.onSubscriptionsChanged(); 341 } 342 } 343 344 /** Clears the local cache of roaming subscription Ids used by {@link #isNetworkRoaming}. */ clearNetworkRoamingStatus()345 public void clearNetworkRoamingStatus() { 346 roamingSimSubscriptionIds.clear(); 347 } 348 349 /** 350 * If isNetworkRoaming is set, it will mark the provided sim subscriptionId as roaming in a local 351 * cache. If isNetworkRoaming is unset it will remove the subscriptionId from the local cache. The 352 * local cache is used to provide roaming status returned by {@link #isNetworkRoaming}. 353 */ setNetworkRoamingStatus(int simSubscriptionId, boolean isNetworkRoaming)354 public void setNetworkRoamingStatus(int simSubscriptionId, boolean isNetworkRoaming) { 355 if (isNetworkRoaming) { 356 roamingSimSubscriptionIds.add(simSubscriptionId); 357 } else { 358 roamingSimSubscriptionIds.remove(simSubscriptionId); 359 } 360 } 361 362 /** 363 * Uses the local cache of roaming sim subscription Ids managed by {@link 364 * #setNetworkRoamingStatus} to return subscription Ids marked as roaming. Otherwise subscription 365 * Ids will be considered as non-roaming if they are not in the cache. 366 */ 367 @Implementation(minSdk = LOLLIPOP_MR1) isNetworkRoaming(int simSubscriptionId)368 protected boolean isNetworkRoaming(int simSubscriptionId) { 369 return roamingSimSubscriptionIds.contains(simSubscriptionId); 370 } 371 372 /** Adds a subscription ID-phone ID mapping to the map used by {@link getPhoneId}. */ putPhoneId(int subId, int phoneId)373 public static void putPhoneId(int subId, int phoneId) { 374 phoneIds.put(subId, phoneId); 375 } 376 377 /** 378 * Removes a subscription ID-phone ID mapping from the map used by {@link getPhoneId}. 379 * 380 * @return the previous phone ID associated with the subscription ID, or null if there was no 381 * mapping for the subscription ID 382 */ removePhoneId(int subId)383 public static Integer removePhoneId(int subId) { 384 return phoneIds.remove(subId); 385 } 386 387 /** 388 * Removes all mappings between subscription IDs and phone IDs from the map used by {@link 389 * getPhoneId}. 390 */ clearPhoneIds()391 public static void clearPhoneIds() { 392 phoneIds.clear(); 393 } 394 395 /** 396 * Uses the map of subscription IDs to phone IDs managed by {@link putPhoneId} and {@link 397 * removePhoneId} to return the phone ID for a given subscription ID. 398 */ 399 @Implementation(minSdk = LOLLIPOP_MR1, maxSdk = P) 400 @HiddenApi getPhoneId(int subId)401 protected static int getPhoneId(int subId) { 402 if (phoneIds.containsKey(subId)) { 403 return phoneIds.get(subId); 404 } 405 return INVALID_PHONE_INDEX; 406 } 407 408 /** 409 * When set to false methods requiring {@link android.Manifest.permission.READ_PHONE_STATE} 410 * permission will throw a {@link SecurityException}. By default it's set to true for backwards 411 * compatibility. 412 */ setReadPhoneStatePermission(boolean readPhoneStatePermission)413 public void setReadPhoneStatePermission(boolean readPhoneStatePermission) { 414 this.readPhoneStatePermission = readPhoneStatePermission; 415 } 416 checkReadPhoneStatePermission()417 private void checkReadPhoneStatePermission() { 418 if (!readPhoneStatePermission) { 419 throw new SecurityException(); 420 } 421 } 422 423 /** 424 * When set to false methods requiring {@link android.Manifest.permission.READ_PHONE_NUMBERS} 425 * permission will throw a {@link SecurityException}. By default it's set to true for backwards 426 * compatibility. 427 */ setReadPhoneNumbersPermission(boolean readPhoneNumbersPermission)428 public void setReadPhoneNumbersPermission(boolean readPhoneNumbersPermission) { 429 this.readPhoneNumbersPermission = readPhoneNumbersPermission; 430 } 431 checkReadPhoneNumbersPermission()432 private void checkReadPhoneNumbersPermission() { 433 if (!readPhoneNumbersPermission) { 434 throw new SecurityException(); 435 } 436 } 437 438 /** 439 * Returns the phone number for the given {@code subscriptionId}, or an empty string if not 440 * available. 441 * 442 * <p>The phone number can be set by {@link #setPhoneNumber(int, String)} 443 * 444 * <p>An exception will be thrown if the READ_PHONE_NUMBERS permission has not been granted. 445 */ 446 @Implementation(minSdk = TIRAMISU) getPhoneNumber(int subscriptionId)447 protected String getPhoneNumber(int subscriptionId) { 448 checkReadPhoneNumbersPermission(); 449 return phoneNumberMap.getOrDefault(subscriptionId, ""); 450 } 451 452 /** 453 * Returns the phone number for the given {@code subscriptionId}, or an empty string if not 454 * available. {@code source} is ignored and will return the same as {@link #getPhoneNumber(int)}. 455 * 456 * <p>The phone number can be set by {@link #setPhoneNumber(int, String)} 457 */ 458 @Implementation(minSdk = TIRAMISU) getPhoneNumber(int subscriptionId, int source)459 protected String getPhoneNumber(int subscriptionId, int source) { 460 return getPhoneNumber(subscriptionId); 461 } 462 463 /** Sets the phone number returned by {@link #getPhoneNumber(int)}. */ setPhoneNumber(int subscriptionId, String phoneNumber)464 public void setPhoneNumber(int subscriptionId, String phoneNumber) { 465 phoneNumberMap.put(subscriptionId, phoneNumber); 466 } 467 468 @Resetter reset()469 public static void reset() { 470 activeDataSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; 471 defaultDataSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; 472 defaultSmsSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; 473 defaultVoiceSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; 474 defaultSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; 475 phoneIds.clear(); 476 } 477 478 /** Builder class to create instance of {@link SubscriptionInfo}. */ 479 public static class SubscriptionInfoBuilder { 480 private final SubscriptionInfo subscriptionInfo = 481 ReflectionHelpers.callConstructor(SubscriptionInfo.class); 482 newBuilder()483 public static SubscriptionInfoBuilder newBuilder() { 484 return new SubscriptionInfoBuilder(); 485 } 486 buildSubscriptionInfo()487 public SubscriptionInfo buildSubscriptionInfo() { 488 return subscriptionInfo; 489 } 490 setId(int id)491 public SubscriptionInfoBuilder setId(int id) { 492 ReflectionHelpers.setField(subscriptionInfo, "mId", id); 493 return this; 494 } 495 setIccId(String iccId)496 public SubscriptionInfoBuilder setIccId(String iccId) { 497 ReflectionHelpers.setField(subscriptionInfo, "mIccId", iccId); 498 return this; 499 } 500 setSimSlotIndex(int index)501 public SubscriptionInfoBuilder setSimSlotIndex(int index) { 502 ReflectionHelpers.setField(subscriptionInfo, "mSimSlotIndex", index); 503 return this; 504 } 505 setDisplayName(String name)506 public SubscriptionInfoBuilder setDisplayName(String name) { 507 ReflectionHelpers.setField(subscriptionInfo, "mDisplayName", name); 508 return this; 509 } 510 setCarrierName(String carrierName)511 public SubscriptionInfoBuilder setCarrierName(String carrierName) { 512 ReflectionHelpers.setField(subscriptionInfo, "mCarrierName", carrierName); 513 return this; 514 } 515 setIconTint(int iconTint)516 public SubscriptionInfoBuilder setIconTint(int iconTint) { 517 ReflectionHelpers.setField(subscriptionInfo, "mIconTint", iconTint); 518 return this; 519 } 520 setNumber(String number)521 public SubscriptionInfoBuilder setNumber(String number) { 522 ReflectionHelpers.setField(subscriptionInfo, "mNumber", number); 523 return this; 524 } 525 setDataRoaming(int dataRoaming)526 public SubscriptionInfoBuilder setDataRoaming(int dataRoaming) { 527 ReflectionHelpers.setField(subscriptionInfo, "mDataRoaming", dataRoaming); 528 return this; 529 } 530 setCountryIso(String countryIso)531 public SubscriptionInfoBuilder setCountryIso(String countryIso) { 532 ReflectionHelpers.setField(subscriptionInfo, "mCountryIso", countryIso); 533 return this; 534 } 535 setProfileClass(int profileClass)536 public SubscriptionInfoBuilder setProfileClass(int profileClass) { 537 ReflectionHelpers.setField(subscriptionInfo, "mProfileClass", profileClass); 538 return this; 539 } 540 setIsEmbedded(boolean isEmbedded)541 public SubscriptionInfoBuilder setIsEmbedded(boolean isEmbedded) { 542 ReflectionHelpers.setField(subscriptionInfo, "mIsEmbedded", isEmbedded); 543 return this; 544 } 545 setIsOpportunistic(boolean isOpportunistic)546 public SubscriptionInfoBuilder setIsOpportunistic(boolean isOpportunistic) { 547 ReflectionHelpers.setField(subscriptionInfo, "mIsOpportunistic", isOpportunistic); 548 return this; 549 } 550 setMnc(String mnc)551 public SubscriptionInfoBuilder setMnc(String mnc) { 552 if (VERSION.SDK_INT < Q) { 553 ReflectionHelpers.setField(subscriptionInfo, "mMnc", Integer.valueOf(mnc)); 554 } else { 555 ReflectionHelpers.setField(subscriptionInfo, "mMnc", mnc); 556 } 557 return this; 558 } 559 setMcc(String mcc)560 public SubscriptionInfoBuilder setMcc(String mcc) { 561 if (VERSION.SDK_INT < Q) { 562 ReflectionHelpers.setField(subscriptionInfo, "mMcc", Integer.valueOf(mcc)); 563 } else { 564 ReflectionHelpers.setField(subscriptionInfo, "mMcc", mcc); 565 } 566 return this; 567 } 568 569 // Use {@link #newBuilder} to construct builders. SubscriptionInfoBuilder()570 private SubscriptionInfoBuilder() {} 571 } 572 } 573