• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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