Home | History | Annotate | Download | only in shadows
      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)
     31   protected static int getDefaultSubscriptionId() {
     32     return defaultSubscriptionId;
     33   }
     34 
     35   /** Returns value set with {@link #setDefaultDataSubscriptionId(int)}. */
     36   @Implementation(minSdk = N)
     37   protected static int getDefaultDataSubscriptionId() {
     38     return defaultDataSubscriptionId;
     39   }
     40 
     41   /** Returns value set with {@link #setDefaultSmsSubscriptionId(int)}. */
     42   @Implementation(minSdk = N)
     43   protected static int getDefaultSmsSubscriptionId() {
     44     return defaultSmsSubscriptionId;
     45   }
     46 
     47   /** Returns value set with {@link #setDefaultVoiceSubscriptionId(int)}. */
     48   @Implementation(minSdk = N)
     49   protected static int getDefaultVoiceSubscriptionId() {
     50     return defaultVoiceSubscriptionId;
     51   }
     52 
     53   /** Sets the value that will be returned by {@link #getDefaultSubscriptionId()}. */
     54   public static void setDefaultSubscriptionId(int defaultSubscriptionId) {
     55     ShadowSubscriptionManager.defaultSubscriptionId = defaultSubscriptionId;
     56   }
     57 
     58   public static void setDefaultDataSubscriptionId(int defaultDataSubscriptionId) {
     59     ShadowSubscriptionManager.defaultDataSubscriptionId = defaultDataSubscriptionId;
     60   }
     61 
     62   public static void setDefaultSmsSubscriptionId(int defaultSmsSubscriptionId) {
     63     ShadowSubscriptionManager.defaultSmsSubscriptionId = defaultSmsSubscriptionId;
     64   }
     65 
     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)
     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)
    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)
    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)
    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    */
    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    */
    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)
    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)
    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
    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    */
    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}. */
    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    */
    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)
    227   protected boolean isNetworkRoaming(int simSubscriptionId) {
    228     return roamingSimSubscriptionIds.contains(simSubscriptionId);
    229   }
    230 
    231   @Resetter
    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 
    244     public static SubscriptionInfoBuilder newBuilder() {
    245       return new SubscriptionInfoBuilder();
    246     }
    247 
    248     public SubscriptionInfo buildSubscriptionInfo() {
    249       return subscriptionInfo;
    250     }
    251 
    252     public SubscriptionInfoBuilder setId(int id) {
    253       ReflectionHelpers.setField(subscriptionInfo, "mId", id);
    254       return this;
    255     }
    256 
    257     public SubscriptionInfoBuilder setIccId(String iccId) {
    258       ReflectionHelpers.setField(subscriptionInfo, "mIccId", iccId);
    259       return this;
    260     }
    261 
    262     public SubscriptionInfoBuilder setSimSlotIndex(int index) {
    263       ReflectionHelpers.setField(subscriptionInfo, "mSimSlotIndex", index);
    264       return this;
    265     }
    266 
    267     public SubscriptionInfoBuilder setDisplayName(String name) {
    268       ReflectionHelpers.setField(subscriptionInfo, "mDisplayName", name);
    269       return this;
    270     }
    271 
    272     public SubscriptionInfoBuilder setCarrierName(String carrierName) {
    273       ReflectionHelpers.setField(subscriptionInfo, "mCarrierName", carrierName);
    274       return this;
    275     }
    276 
    277     public SubscriptionInfoBuilder setIconTint(int iconTint) {
    278       ReflectionHelpers.setField(subscriptionInfo, "mIconTint", iconTint);
    279       return this;
    280     }
    281 
    282     public SubscriptionInfoBuilder setNumber(String number) {
    283       ReflectionHelpers.setField(subscriptionInfo, "mNumber", number);
    284       return this;
    285     }
    286 
    287     public SubscriptionInfoBuilder setDataRoaming(int dataRoaming) {
    288       ReflectionHelpers.setField(subscriptionInfo, "mDataRoaming", dataRoaming);
    289       return this;
    290     }
    291 
    292     public SubscriptionInfoBuilder setCountryIso(String countryIso) {
    293       ReflectionHelpers.setField(subscriptionInfo, "mCountryIso", countryIso);
    294       return this;
    295     }
    296 
    297     // Use {@link #newBuilder} to construct builders.
    298     private SubscriptionInfoBuilder() {}
    299   }
    300 }
    301