• 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.N;
5 
6 import android.telephony.SubscriptionInfo;
7 import android.telephony.SubscriptionManager;
8 import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
9 import java.util.ArrayList;
10 import java.util.Arrays;
11 import java.util.Collections;
12 import java.util.HashSet;
13 import java.util.List;
14 import java.util.Set;
15 import org.robolectric.annotation.HiddenApi;
16 import org.robolectric.annotation.Implementation;
17 import org.robolectric.annotation.Implements;
18 import org.robolectric.annotation.Resetter;
19 import org.robolectric.util.ReflectionHelpers;
20 
21 @Implements(value = SubscriptionManager.class, minSdk = LOLLIPOP_MR1)
22 public class ShadowSubscriptionManager {
23 
24   private static int defaultSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
25   private static int defaultDataSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
26   private static int defaultSmsSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
27   private static int defaultVoiceSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
28 
29   /** Returns value set with {@link #setDefaultSubscriptionId(int)}. */
30   @Implementation(minSdk = N)
getDefaultSubscriptionId()31   protected static int getDefaultSubscriptionId() {
32     return defaultSubscriptionId;
33   }
34 
35   /** Returns value set with {@link #setDefaultDataSubscriptionId(int)}. */
36   @Implementation(minSdk = N)
getDefaultDataSubscriptionId()37   protected static int getDefaultDataSubscriptionId() {
38     return defaultDataSubscriptionId;
39   }
40 
41   /** Returns value set with {@link #setDefaultSmsSubscriptionId(int)}. */
42   @Implementation(minSdk = N)
getDefaultSmsSubscriptionId()43   protected static int getDefaultSmsSubscriptionId() {
44     return defaultSmsSubscriptionId;
45   }
46 
47   /** Returns value set with {@link #setDefaultVoiceSubscriptionId(int)}. */
48   @Implementation(minSdk = N)
getDefaultVoiceSubscriptionId()49   protected static int getDefaultVoiceSubscriptionId() {
50     return defaultVoiceSubscriptionId;
51   }
52 
53   /** Sets the value that will be returned by {@link #getDefaultSubscriptionId()}. */
setDefaultSubscriptionId(int defaultSubscriptionId)54   public static void setDefaultSubscriptionId(int defaultSubscriptionId) {
55     ShadowSubscriptionManager.defaultSubscriptionId = defaultSubscriptionId;
56   }
57 
setDefaultDataSubscriptionId(int defaultDataSubscriptionId)58   public static void setDefaultDataSubscriptionId(int defaultDataSubscriptionId) {
59     ShadowSubscriptionManager.defaultDataSubscriptionId = defaultDataSubscriptionId;
60   }
61 
setDefaultSmsSubscriptionId(int defaultSmsSubscriptionId)62   public static void setDefaultSmsSubscriptionId(int defaultSmsSubscriptionId) {
63     ShadowSubscriptionManager.defaultSmsSubscriptionId = defaultSmsSubscriptionId;
64   }
65 
setDefaultVoiceSubscriptionId(int defaultVoiceSubscriptionId)66   public static void setDefaultVoiceSubscriptionId(int defaultVoiceSubscriptionId) {
67     ShadowSubscriptionManager.defaultVoiceSubscriptionId = defaultVoiceSubscriptionId;
68   }
69 
70   /**
71    * Cache of {@link SubscriptionInfo} used by {@link #getActiveSubscriptionInfoList}.
72    * Managed by {@link #setActiveSubscriptionInfoList}.
73    */
74   private List<SubscriptionInfo> subscriptionList = new ArrayList<>();
75   /**
76    * List of listeners to be notified if the list of {@link SubscriptionInfo} changes. Managed by
77    * {@link #addOnSubscriptionsChangedListener} and {@link removeOnSubscriptionsChangedListener}.
78    */
79   private List<OnSubscriptionsChangedListener> listeners = new ArrayList<>();
80   /**
81    * Cache of subscription ids used by {@link #isNetworkRoaming}. Managed by {@link
82    * #setNetworkRoamingStatus} and {@link #clearNetworkRoamingStatus}.
83    */
84   private Set<Integer> roamingSimSubscriptionIds = new HashSet<>();
85 
86   /**
87    * Returns the active list of {@link SubscriptionInfo} that were set via {@link
88    * #setActiveSubscriptionInfoList}.
89    */
90   @Implementation(minSdk = LOLLIPOP_MR1)
getActiveSubscriptionInfoList()91   protected List<SubscriptionInfo> getActiveSubscriptionInfoList() {
92     return subscriptionList;
93   }
94 
95   /**
96    * Returns the size of the list of {@link SubscriptionInfo} that were set via {@link
97    * #setActiveSubscriptionInfoList}. If no list was set, returns 0.
98    */
99   @Implementation(minSdk = LOLLIPOP_MR1)
getActiveSubscriptionInfoCount()100   protected int getActiveSubscriptionInfoCount() {
101     return subscriptionList == null ? 0 : subscriptionList.size();
102   }
103 
104   /**
105    * Returns subscription that were set via {@link #setActiveSubscriptionInfoList} if it can find
106    * one with the specified id or null if none found.
107    */
108   @Implementation(minSdk = LOLLIPOP_MR1)
getActiveSubscriptionInfo(int subId)109   protected SubscriptionInfo getActiveSubscriptionInfo(int subId) {
110     if (subscriptionList == null) {
111       return null;
112     }
113     for (SubscriptionInfo info : subscriptionList) {
114       if (info.getSubscriptionId() == subId) {
115         return info;
116       }
117     }
118     return null;
119   }
120 
121   /**
122    * Returns subscription that were set via {@link #setActiveSubscriptionInfoList} if it can find
123    * one with the specified slot index or null if none found.
124    */
125   @Implementation(minSdk = N)
getActiveSubscriptionInfoForSimSlotIndex(int slotIndex)126   protected SubscriptionInfo getActiveSubscriptionInfoForSimSlotIndex(int slotIndex) {
127     if (subscriptionList == null) {
128       return null;
129     }
130     for (SubscriptionInfo info : subscriptionList) {
131       if (info.getSimSlotIndex() == slotIndex) {
132         return info;
133       }
134     }
135     return null;
136   }
137 
138   /**
139    * Sets the active list of {@link SubscriptionInfo}. This call internally triggers {@link
140    * OnSubscriptionsChangedListener#onSubscriptionsChanged()} to all the listeners.
141    * @param list - The subscription info list, can be null.
142    */
setActiveSubscriptionInfoList(List<SubscriptionInfo> list)143   public void setActiveSubscriptionInfoList(List<SubscriptionInfo> list) {
144     subscriptionList = list;
145     dispatchOnSubscriptionsChanged();
146   }
147 
148   /**
149    * Sets the active list of {@link SubscriptionInfo}. This call internally triggers {@link
150    * OnSubscriptionsChangedListener#onSubscriptionsChanged()} to all the listeners.
151    */
setActiveSubscriptionInfos(SubscriptionInfo... infos)152   public void setActiveSubscriptionInfos(SubscriptionInfo... infos) {
153     if (infos == null) {
154       setActiveSubscriptionInfoList(Collections.emptyList());
155     } else {
156       setActiveSubscriptionInfoList(Arrays.asList(infos));
157     }
158   }
159 
160   /**
161    * Adds a listener to a local list of listeners. Will be triggered by {@link
162    * #setActiveSubscriptionInfoList} when the local list of {@link SubscriptionInfo} is updated.
163    */
164   @Implementation(minSdk = LOLLIPOP_MR1)
addOnSubscriptionsChangedListener(OnSubscriptionsChangedListener listener)165   protected void addOnSubscriptionsChangedListener(OnSubscriptionsChangedListener listener) {
166     listeners.add(listener);
167   }
168 
169   /**
170    * Removes a listener from a local list of listeners. Will be triggered by {@link
171    * #setActiveSubscriptionInfoList} when the local list of {@link SubscriptionInfo} is updated.
172    */
173   @Implementation(minSdk = LOLLIPOP_MR1)
removeOnSubscriptionsChangedListener(OnSubscriptionsChangedListener listener)174   protected void removeOnSubscriptionsChangedListener(OnSubscriptionsChangedListener listener) {
175     listeners.remove(listener);
176   }
177 
178   /** Returns subscription Ids that were set via {@link #setActiveSubscriptionInfoList}. */
179   @Implementation(minSdk = LOLLIPOP_MR1)
180   @HiddenApi
getActiveSubscriptionIdList()181   protected int[] getActiveSubscriptionIdList() {
182     final List<SubscriptionInfo> infos = getActiveSubscriptionInfoList();
183     if (infos == null) {
184       return new int[0];
185     }
186     int[] ids = new int[infos.size()];
187     for (int i = 0; i < infos.size(); i++) {
188       ids[i] = infos.get(i).getSubscriptionId();
189     }
190     return ids;
191   }
192 
193   /**
194    * Notifies {@link OnSubscriptionsChangedListener} listeners that the list of {@link
195    * SubscriptionInfo} has been updated.
196    */
dispatchOnSubscriptionsChanged()197   private void dispatchOnSubscriptionsChanged() {
198     for (OnSubscriptionsChangedListener listener : listeners) {
199       listener.onSubscriptionsChanged();
200     }
201   }
202 
203   /** Clears the local cache of roaming subscription Ids used by {@link #isNetworkRoaming}. */
clearNetworkRoamingStatus()204   public void clearNetworkRoamingStatus(){
205     roamingSimSubscriptionIds.clear();
206   }
207 
208   /**
209    * If isNetworkRoaming is set, it will mark the provided sim subscriptionId as roaming in a local
210    * cache. If isNetworkRoaming is unset it will remove the subscriptionId from the local cache. The
211    * local cache is used to provide roaming status returned by {@link #isNetworkRoaming}.
212    */
setNetworkRoamingStatus(int simSubscriptionId, boolean isNetworkRoaming)213   public void setNetworkRoamingStatus(int simSubscriptionId, boolean isNetworkRoaming) {
214     if (isNetworkRoaming) {
215       roamingSimSubscriptionIds.add(simSubscriptionId);
216     } else {
217       roamingSimSubscriptionIds.remove(simSubscriptionId);
218     }
219   }
220 
221   /**
222    * Uses the local cache of roaming sim subscription Ids managed by {@link
223    * #setNetworkRoamingStatus} to return subscription Ids marked as roaming. Otherwise subscription
224    * Ids will be considered as non-roaming if they are not in the cache.
225    */
226   @Implementation(minSdk = LOLLIPOP_MR1)
isNetworkRoaming(int simSubscriptionId)227   protected boolean isNetworkRoaming(int simSubscriptionId) {
228     return roamingSimSubscriptionIds.contains(simSubscriptionId);
229   }
230 
231   @Resetter
reset()232   public static void reset() {
233     defaultDataSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
234     defaultSmsSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
235     defaultVoiceSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
236     defaultSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
237   }
238 
239   /** Builder class to create instance of {@link SubscriptionInfo}. */
240   public static class SubscriptionInfoBuilder {
241     private final SubscriptionInfo subscriptionInfo =
242         ReflectionHelpers.callConstructor(SubscriptionInfo.class);
243 
newBuilder()244     public static SubscriptionInfoBuilder newBuilder() {
245       return new SubscriptionInfoBuilder();
246     }
247 
buildSubscriptionInfo()248     public SubscriptionInfo buildSubscriptionInfo() {
249       return subscriptionInfo;
250     }
251 
setId(int id)252     public SubscriptionInfoBuilder setId(int id) {
253       ReflectionHelpers.setField(subscriptionInfo, "mId", id);
254       return this;
255     }
256 
setIccId(String iccId)257     public SubscriptionInfoBuilder setIccId(String iccId) {
258       ReflectionHelpers.setField(subscriptionInfo, "mIccId", iccId);
259       return this;
260     }
261 
setSimSlotIndex(int index)262     public SubscriptionInfoBuilder setSimSlotIndex(int index) {
263       ReflectionHelpers.setField(subscriptionInfo, "mSimSlotIndex", index);
264       return this;
265     }
266 
setDisplayName(String name)267     public SubscriptionInfoBuilder setDisplayName(String name) {
268       ReflectionHelpers.setField(subscriptionInfo, "mDisplayName", name);
269       return this;
270     }
271 
setCarrierName(String carrierName)272     public SubscriptionInfoBuilder setCarrierName(String carrierName) {
273       ReflectionHelpers.setField(subscriptionInfo, "mCarrierName", carrierName);
274       return this;
275     }
276 
setIconTint(int iconTint)277     public SubscriptionInfoBuilder setIconTint(int iconTint) {
278       ReflectionHelpers.setField(subscriptionInfo, "mIconTint", iconTint);
279       return this;
280     }
281 
setNumber(String number)282     public SubscriptionInfoBuilder setNumber(String number) {
283       ReflectionHelpers.setField(subscriptionInfo, "mNumber", number);
284       return this;
285     }
286 
setDataRoaming(int dataRoaming)287     public SubscriptionInfoBuilder setDataRoaming(int dataRoaming) {
288       ReflectionHelpers.setField(subscriptionInfo, "mDataRoaming", dataRoaming);
289       return this;
290     }
291 
setCountryIso(String countryIso)292     public SubscriptionInfoBuilder setCountryIso(String countryIso) {
293       ReflectionHelpers.setField(subscriptionInfo, "mCountryIso", countryIso);
294       return this;
295     }
296 
297     // Use {@link #newBuilder} to construct builders.
SubscriptionInfoBuilder()298     private SubscriptionInfoBuilder() {}
299   }
300 }
301