Home | History | Annotate | Download | only in shadows
      1 package org.robolectric.shadows;
      2 
      3 import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
      4 import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR2;
      5 import static android.os.Build.VERSION_CODES.LOLLIPOP;
      6 import static android.os.Build.VERSION_CODES.M;
      7 import static android.os.Build.VERSION_CODES.N;
      8 import static android.os.Build.VERSION_CODES.O;
      9 import static android.os.Build.VERSION_CODES.P;
     10 import static android.telephony.PhoneStateListener.LISTEN_CALL_STATE;
     11 import static android.telephony.PhoneStateListener.LISTEN_CELL_INFO;
     12 import static android.telephony.PhoneStateListener.LISTEN_CELL_LOCATION;
     13 import static android.telephony.PhoneStateListener.LISTEN_NONE;
     14 import static android.telephony.TelephonyManager.CALL_STATE_IDLE;
     15 import static android.telephony.TelephonyManager.CALL_STATE_RINGING;
     16 
     17 import android.content.Intent;
     18 import android.net.Uri;
     19 import android.os.Build;
     20 import android.os.Build.VERSION;
     21 import android.os.PersistableBundle;
     22 import android.telecom.PhoneAccountHandle;
     23 import android.telephony.CellInfo;
     24 import android.telephony.CellLocation;
     25 import android.telephony.PhoneStateListener;
     26 import android.telephony.ServiceState;
     27 import android.telephony.SubscriptionManager;
     28 import android.telephony.TelephonyManager;
     29 import android.util.SparseArray;
     30 import android.util.SparseIntArray;
     31 import com.google.common.base.Predicate;
     32 import com.google.common.collect.Iterables;
     33 import java.util.Collections;
     34 import java.util.HashMap;
     35 import java.util.List;
     36 import java.util.Map;
     37 import org.robolectric.annotation.HiddenApi;
     38 import org.robolectric.annotation.Implementation;
     39 import org.robolectric.annotation.Implements;
     40 
     41 @Implements(TelephonyManager.class)
     42 public class ShadowTelephonyManager {
     43 
     44   private final Map<PhoneStateListener, Integer> phoneStateRegistrations = new HashMap<>();
     45   private final Map<Integer, String> slotIndexToDeviceId = new HashMap<>();
     46   private final Map<PhoneAccountHandle, Boolean> voicemailVibrationEnabledMap = new HashMap<>();
     47   private final Map<PhoneAccountHandle, Uri> voicemailRingtoneUriMap = new HashMap<>();
     48   private final Map<PhoneAccountHandle, TelephonyManager> phoneAccountToTelephonyManagers =
     49       new HashMap<>();
     50 
     51   private PhoneStateListener lastListener;
     52   private int lastEventFlags;
     53 
     54   private String deviceId;
     55   private String imei;
     56   private String meid;
     57   private String groupIdLevel1;
     58   private String networkOperatorName = "";
     59   private String networkCountryIso;
     60   private String networkOperator = "";
     61   private String simOperator;
     62   private String simOperatorName;
     63   private String simSerialNumber;
     64   private boolean readPhoneStatePermission = true;
     65   private int phoneType = TelephonyManager.PHONE_TYPE_GSM;
     66   private String line1Number;
     67   private int networkType;
     68   private int voiceNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
     69   private List<CellInfo> allCellInfo = Collections.emptyList();
     70   private CellLocation cellLocation = null;
     71   private int callState = CALL_STATE_IDLE;
     72   private String incomingPhoneNumber = null;
     73   private boolean isAnasEnabled;
     74   private boolean isSmsCapable = true;
     75   private String voiceMailNumber;
     76   private String voiceMailAlphaTag;
     77   private int phoneCount = 1;
     78   private Map<Integer, TelephonyManager> subscriptionIdsToTelephonyManagers = new HashMap<>();
     79   private PersistableBundle carrierConfig;
     80   private ServiceState serviceState;
     81   private boolean isNetworkRoaming;
     82   private final SparseIntArray simStates = new SparseIntArray();
     83   private final SparseIntArray currentPhoneTypes = new SparseIntArray();
     84   private final SparseArray<List<String>> carrierPackageNames = new SparseArray<>();
     85   private final Map<Integer, String> simCountryIsoMap = new HashMap<>();
     86   private int simCarrierId;
     87   private String subscriberId;
     88 
     89   {
     90     resetSimStates();
     91     resetSimCountryIsos();
     92   }
     93 
     94   @Implementation
     95   protected void listen(PhoneStateListener listener, int flags) {
     96     lastListener = listener;
     97     lastEventFlags = flags;
     98 
     99     if (flags == LISTEN_NONE) {
    100       phoneStateRegistrations.remove(listener);
    101     } else {
    102       initListener(listener, flags);
    103       phoneStateRegistrations.put(listener, flags);
    104     }
    105   }
    106 
    107   /**
    108    * Returns the most recent listener passed to #listen().
    109    *
    110    * @return Phone state listener.
    111    * @deprecated Avoid using.
    112    */
    113   @Deprecated
    114   public PhoneStateListener getListener() {
    115     return lastListener;
    116   }
    117 
    118   /**
    119    * Returns the most recent flags passed to #listen().
    120    *
    121    * @return Event flags.
    122    * @deprecated Avoid using.
    123    */
    124   @Deprecated
    125   public int getEventFlags() {
    126     return lastEventFlags;
    127   }
    128 
    129   /** Call state may be specified via {@link #setCallState(int)}. */
    130   @Implementation
    131   protected int getCallState() {
    132     return callState;
    133   }
    134 
    135   /** Sets the current call state to the desired state and updates any listeners. */
    136   public void setCallState(int callState) {
    137     setCallState(callState, null);
    138   }
    139 
    140   /**
    141    * Sets the current call state with the option to specify an incoming phone number for the
    142    * CALL_STATE_RINGING state. The incoming phone number will be ignored for all other cases.
    143    */
    144   public void setCallState(int callState, String incomingPhoneNumber) {
    145     if (callState != CALL_STATE_RINGING) {
    146       incomingPhoneNumber = null;
    147     }
    148 
    149     this.callState = callState;
    150     this.incomingPhoneNumber = incomingPhoneNumber;
    151 
    152     for (PhoneStateListener listener : getListenersForFlags(LISTEN_CALL_STATE)) {
    153       listener.onCallStateChanged(callState, incomingPhoneNumber);
    154     }
    155   }
    156 
    157   @Implementation
    158   protected String getDeviceId() {
    159     checkReadPhoneStatePermission();
    160     return deviceId;
    161   }
    162 
    163   public void setDeviceId(String newDeviceId) {
    164     deviceId = newDeviceId;
    165   }
    166 
    167   public void setNetworkOperatorName(String networkOperatorName) {
    168     this.networkOperatorName = networkOperatorName;
    169   }
    170 
    171   @Implementation(minSdk = LOLLIPOP)
    172   protected String getImei() {
    173     checkReadPhoneStatePermission();
    174     return imei;
    175   }
    176 
    177   /** Set the IMEI returned by getImei(). */
    178   public void setImei(String imei) {
    179     this.imei = imei;
    180   }
    181 
    182   @Implementation(minSdk = O)
    183   protected String getMeid() {
    184     checkReadPhoneStatePermission();
    185     return meid;
    186   }
    187 
    188   /** Set the MEID returned by getMeid(). */
    189   public void setMeid(String meid) {
    190     this.meid = meid;
    191   }
    192 
    193   @Implementation
    194   protected String getNetworkOperatorName() {
    195     return networkOperatorName;
    196   }
    197 
    198   public void setNetworkCountryIso(String networkCountryIso) {
    199     this.networkCountryIso = networkCountryIso;
    200   }
    201 
    202   @Implementation
    203   protected String getNetworkCountryIso() {
    204     return networkCountryIso;
    205   }
    206 
    207   public void setNetworkOperator(String networkOperator) {
    208     this.networkOperator = networkOperator;
    209   }
    210 
    211   @Implementation
    212   protected String getNetworkOperator() {
    213     return networkOperator;
    214   }
    215 
    216   @Implementation
    217   protected String getSimOperator() {
    218     return simOperator;
    219   }
    220 
    221   public void setSimOperator(String simOperator) {
    222     this.simOperator = simOperator;
    223   }
    224 
    225   @Implementation
    226   protected String getSimOperatorName() {
    227     return simOperatorName;
    228   }
    229 
    230   public void setSimOperatorName(String simOperatorName) {
    231     this.simOperatorName = simOperatorName;
    232   }
    233 
    234   @Implementation
    235   protected String getSimSerialNumber() {
    236     checkReadPhoneStatePermission();
    237     return this.simSerialNumber;
    238   }
    239 
    240   /** sets the serial number that will be returned by {@link #getSimSerialNumber}. */
    241   public void setSimSerialNumber(String simSerialNumber) {
    242     this.simSerialNumber = simSerialNumber;
    243   }
    244 
    245   @Implementation
    246   protected String getSimCountryIso() {
    247     return simCountryIsoMap.get(/* subId= */ 0);
    248   }
    249 
    250   @Implementation(minSdk = N)
    251   @HiddenApi
    252   protected String getSimCountryIso(int subId) {
    253     return simCountryIsoMap.get(subId);
    254   }
    255 
    256   public void setSimCountryIso(String simCountryIso) {
    257     setSimCountryIso(/* subId= */ 0, simCountryIso);
    258   }
    259 
    260   /** Sets the {@code simCountryIso} for the given {@code subId}. */
    261   public void setSimCountryIso(int subId, String simCountryIso) {
    262     simCountryIsoMap.put(subId, simCountryIso);
    263   }
    264 
    265   /** Clears {@code subId} to simCountryIso mapping and resets to default state. */
    266   public void resetSimCountryIsos() {
    267     simCountryIsoMap.clear();
    268     simCountryIsoMap.put(0, "");
    269   }
    270 
    271   @Implementation
    272   protected int getSimState() {
    273     return getSimState(/* slotIndex= */ 0);
    274   }
    275 
    276   /** Sets the sim state of slot 0. */
    277   public void setSimState(int simState) {
    278     setSimState(/* slotIndex= */ 0, simState);
    279   }
    280 
    281   /** Set the sim state for the given {@code slotIndex}. */
    282   public void setSimState(int slotIndex, int state) {
    283     simStates.put(slotIndex, state);
    284   }
    285 
    286   @Implementation(minSdk = O)
    287   protected int getSimState(int slotIndex) {
    288     return simStates.get(slotIndex, TelephonyManager.SIM_STATE_UNKNOWN);
    289   }
    290 
    291   /** Clears {@code slotIndex} to state mapping and resets to default state. */
    292   public void resetSimStates() {
    293     simStates.clear();
    294     simStates.put(0, TelephonyManager.SIM_STATE_READY);
    295   }
    296 
    297   public void setReadPhoneStatePermission(boolean readPhoneStatePermission) {
    298     this.readPhoneStatePermission = readPhoneStatePermission;
    299   }
    300 
    301   private void checkReadPhoneStatePermission() {
    302     if (!readPhoneStatePermission) {
    303       throw new SecurityException();
    304     }
    305   }
    306 
    307   @Implementation
    308   protected int getPhoneType() {
    309     return phoneType;
    310   }
    311 
    312   public void setPhoneType(int phoneType) {
    313     this.phoneType = phoneType;
    314   }
    315 
    316   @Implementation
    317   protected String getLine1Number() {
    318     return line1Number;
    319   }
    320 
    321   public void setLine1Number(String line1Number) {
    322     this.line1Number = line1Number;
    323   }
    324 
    325   @Implementation
    326   protected int getNetworkType() {
    327     return networkType;
    328   }
    329 
    330   public void setNetworkType(int networkType) {
    331     this.networkType = networkType;
    332   }
    333 
    334   /**
    335    * Returns whatever value was set by the last call to {@link #setVoiceNetworkType}, defaulting to
    336    * {@link TelephonyManager#NETWORK_TYPE_UNKNOWN} if it was never called.
    337    */
    338   @Implementation(minSdk = N)
    339   protected int getVoiceNetworkType() {
    340     return voiceNetworkType;
    341   }
    342 
    343   /**
    344    * Sets the value to be returned by calls to {@link getVoiceNetworkType}. This <b>should</b>
    345    * correspond to one of the {@code NETWORK_TYPE_*} constants defined on {@link TelephonyManager},
    346    * but this is not enforced.
    347    */
    348   public void setVoiceNetworkType(int voiceNetworkType) {
    349     this.voiceNetworkType = voiceNetworkType;
    350   }
    351 
    352   @Implementation(minSdk = JELLY_BEAN_MR1)
    353   protected List<CellInfo> getAllCellInfo() {
    354     return allCellInfo;
    355   }
    356 
    357   public void setAllCellInfo(List<CellInfo> allCellInfo) {
    358     this.allCellInfo = allCellInfo;
    359 
    360     if (VERSION.SDK_INT >= JELLY_BEAN_MR1) {
    361       for (PhoneStateListener listener : getListenersForFlags(LISTEN_CELL_INFO)) {
    362         listener.onCellInfoChanged(allCellInfo);
    363       }
    364     }
    365   }
    366 
    367   @Implementation
    368   protected CellLocation getCellLocation() {
    369     return this.cellLocation;
    370   }
    371 
    372   public void setCellLocation(CellLocation cellLocation) {
    373     this.cellLocation = cellLocation;
    374 
    375     for (PhoneStateListener listener : getListenersForFlags(LISTEN_CELL_LOCATION)) {
    376       listener.onCellLocationChanged(cellLocation);
    377     }
    378   }
    379 
    380   @Implementation(minSdk = JELLY_BEAN_MR2)
    381   protected String getGroupIdLevel1() {
    382     return this.groupIdLevel1;
    383   }
    384 
    385   public void setGroupIdLevel1(String groupIdLevel1) {
    386     this.groupIdLevel1 = groupIdLevel1;
    387   }
    388 
    389   private void initListener(PhoneStateListener listener, int flags) {
    390     if ((flags & LISTEN_CALL_STATE) != 0) {
    391       listener.onCallStateChanged(callState, incomingPhoneNumber);
    392     }
    393     if ((flags & LISTEN_CELL_INFO) != 0) {
    394       if (VERSION.SDK_INT >= JELLY_BEAN_MR1) {
    395         listener.onCellInfoChanged(allCellInfo);
    396       }
    397     }
    398     if ((flags & LISTEN_CELL_LOCATION) != 0) {
    399       listener.onCellLocationChanged(cellLocation);
    400     }
    401   }
    402 
    403   private Iterable<PhoneStateListener> getListenersForFlags(int flags) {
    404     return Iterables.filter(
    405         phoneStateRegistrations.keySet(),
    406         new Predicate<PhoneStateListener>() {
    407           @Override
    408           public boolean apply(PhoneStateListener input) {
    409             // only select PhoneStateListeners with matching flags
    410             return (phoneStateRegistrations.get(input) & flags) != 0;
    411           }
    412         });
    413   }
    414 
    415   // BEGIN-INTERNAL
    416   @Implementation(minSdk = Build.VERSION_CODES.Q)
    417   protected boolean setAlternativeNetworkState(boolean enable) {
    418     isAnasEnabled = enable;
    419     return true;
    420   }
    421 
    422   @Implementation(minSdk = Build.VERSION_CODES.Q)
    423   protected boolean isAlternativeNetworkEnabled() {
    424     return isAnasEnabled;
    425   }
    426   // END-INTERNAL
    427 
    428   /** @return `true` by default, or the value specified via {@link #setIsSmsCapable(boolean)} */
    429   @Implementation
    430   protected boolean isSmsCapable() {
    431     return isSmsCapable;
    432   }
    433 
    434   /** Sets the value returned by {@link TelephonyManager#isSmsCapable()}. */
    435   public void setIsSmsCapable(boolean isSmsCapable) {
    436     this.isSmsCapable = isSmsCapable;
    437   }
    438 
    439   /**
    440    * Returns a new empty {@link PersistableBundle} by default, or the value specified via {@link
    441    * #setCarrierConfig(PersistableBundle)}.
    442    */
    443   @Implementation(minSdk = O)
    444   protected PersistableBundle getCarrierConfig() {
    445     return carrierConfig != null ? carrierConfig : new PersistableBundle();
    446   }
    447 
    448   /**
    449    * Sets the value returned by {@link TelephonyManager#getCarrierConfig()}.
    450    *
    451    * @param carrierConfig
    452    */
    453   public void setCarrierConfig(PersistableBundle carrierConfig) {
    454     this.carrierConfig = carrierConfig;
    455   }
    456 
    457   /**
    458    * Returns {@code null} by default, or the value specified via {@link
    459    * #setVoiceMailNumber(String)}.
    460    */
    461   @Implementation
    462   protected String getVoiceMailNumber() {
    463     return voiceMailNumber;
    464   }
    465 
    466   /** Sets the value returned by {@link TelephonyManager#getVoiceMailNumber()}. */
    467   public void setVoiceMailNumber(String voiceMailNumber) {
    468     this.voiceMailNumber = voiceMailNumber;
    469   }
    470 
    471   /**
    472    * Returns {@code null} by default or the value specified via {@link
    473    * #setVoiceMailAlphaTag(String)}.
    474    */
    475   @Implementation
    476   protected String getVoiceMailAlphaTag() {
    477     return voiceMailAlphaTag;
    478   }
    479 
    480   /** Sets the value returned by {@link TelephonyManager#getVoiceMailAlphaTag()}. */
    481   public void setVoiceMailAlphaTag(String voiceMailAlphaTag) {
    482     this.voiceMailAlphaTag = voiceMailAlphaTag;
    483   }
    484 
    485   /** Returns 1 by default or the value specified via {@link #setPhoneCount(int)}. */
    486   @Implementation(minSdk = M)
    487   protected int getPhoneCount() {
    488     return phoneCount;
    489   }
    490 
    491   /** Sets the value returned by {@link TelephonyManager#getPhoneCount()}. */
    492   public void setPhoneCount(int phoneCount) {
    493     this.phoneCount = phoneCount;
    494   }
    495 
    496   /**
    497    * Returns {@code null} by default or the value specified via {@link #setDeviceId(int, String)}.
    498    */
    499   @Implementation(minSdk = M)
    500   protected String getDeviceId(int slot) {
    501     return slotIndexToDeviceId.get(slot);
    502   }
    503 
    504   /** Sets the value returned by {@link TelephonyManager#getDeviceId(int)}. */
    505   public void setDeviceId(int slot, String deviceId) {
    506     slotIndexToDeviceId.put(slot, deviceId);
    507   }
    508 
    509   /**
    510    * Returns {@code null} by default or the value specified via {@link
    511    * #setVoicemailVibrationEnabled(PhoneAccountHandle, boolean)}.
    512    */
    513   @Implementation(minSdk = N)
    514   protected boolean isVoicemailVibrationEnabled(PhoneAccountHandle handle) {
    515     Boolean result = voicemailVibrationEnabledMap.get(handle);
    516     return result != null ? result : false;
    517   }
    518 
    519   /**
    520    * Sets the value returned by {@link
    521    * TelephonyManager#isVoicemailVibrationEnabled(PhoneAccountHandle)}.
    522    */
    523   @Implementation(minSdk = O)
    524   protected void setVoicemailVibrationEnabled(PhoneAccountHandle handle, boolean isEnabled) {
    525     voicemailVibrationEnabledMap.put(handle, isEnabled);
    526   }
    527 
    528   /**
    529    * Returns {@code null} by default or the value specified via {@link
    530    * #setVoicemailRingtoneUri(PhoneAccountHandle, Uri)}.
    531    */
    532   @Implementation(minSdk = N)
    533   protected Uri getVoicemailRingtoneUri(PhoneAccountHandle handle) {
    534     return voicemailRingtoneUriMap.get(handle);
    535   }
    536 
    537   /**
    538    * Sets the value returned by {@link
    539    * TelephonyManager#getVoicemailRingtoneUri(PhoneAccountHandle)}.
    540    */
    541   @Implementation(minSdk = O)
    542   protected void setVoicemailRingtoneUri(PhoneAccountHandle handle, Uri uri) {
    543     voicemailRingtoneUriMap.put(handle, uri);
    544   }
    545 
    546   /**
    547    * Returns {@code null} by default or the value specified via {@link
    548    * #setTelephonyManagerForHandle(PhoneAccountHandle, TelephonyManager)}.
    549    */
    550   @Implementation(minSdk = O)
    551   protected TelephonyManager createForPhoneAccountHandle(PhoneAccountHandle handle) {
    552     return phoneAccountToTelephonyManagers.get(handle);
    553   }
    554 
    555   /**
    556    * Sets the value returned by {@link
    557    * TelephonyManager#createForPhoneAccountHandle(PhoneAccountHandle)}.
    558    */
    559   public void setTelephonyManagerForHandle(
    560       PhoneAccountHandle handle, TelephonyManager telephonyManager) {
    561     phoneAccountToTelephonyManagers.put(handle, telephonyManager);
    562   }
    563 
    564   /**
    565    * Returns {@code null} by default or the value specified via {@link
    566    * #setTelephonyManagerForSubscriptionId(int, TelephonyManager)}
    567    */
    568   @Implementation(minSdk = N)
    569   protected TelephonyManager createForSubscriptionId(int subId) {
    570     return subscriptionIdsToTelephonyManagers.get(subId);
    571   }
    572 
    573   /** Sets the value returned by {@link TelephonyManager#createForSubscriptionId(int)}. */
    574   public void setTelephonyManagerForSubscriptionId(
    575       int subscriptionId, TelephonyManager telephonyManager) {
    576     subscriptionIdsToTelephonyManagers.put(subscriptionId, telephonyManager);
    577   }
    578 
    579   /**
    580    * Returns {@code null} by default or the value specified via {@link
    581    * #setServiceState(ServiceState)}
    582    */
    583   @Implementation(minSdk = O)
    584   protected ServiceState getServiceState() {
    585     return serviceState;
    586   }
    587 
    588   /** Sets the value returned by {@link TelephonyManager#getServiceState()}. */
    589   public void setServiceState(ServiceState serviceState) {
    590     this.serviceState = serviceState;
    591   }
    592 
    593   /**
    594    * Returns {@code false} by default or the value specified via {@link
    595    * #setIsNetworkRoaming(boolean)}
    596    */
    597   @Implementation
    598   protected boolean isNetworkRoaming() {
    599     return isNetworkRoaming;
    600   }
    601 
    602   /** Sets the value returned by {@link TelephonyManager#isNetworkRoaming()}. */
    603   public void setIsNetworkRoaming(boolean isNetworkRoaming) {
    604     this.isNetworkRoaming = isNetworkRoaming;
    605   }
    606 
    607   @Implementation(minSdk = M)
    608   @HiddenApi
    609   protected int getCurrentPhoneType(int subId) {
    610     return currentPhoneTypes.get(subId, TelephonyManager.PHONE_TYPE_NONE);
    611   }
    612 
    613   /** Sets the phone type for the given {@code subId}. */
    614   public void setCurrentPhoneType(int subId, int phoneType) {
    615     currentPhoneTypes.put(subId, phoneType);
    616   }
    617 
    618   /** Removes all {@code subId} to {@code phoneType} mappings. */
    619   public void clearPhoneTypes() {
    620     currentPhoneTypes.clear();
    621   }
    622 
    623   @Implementation(minSdk = M)
    624   @HiddenApi
    625   protected List<String> getCarrierPackageNamesForIntentAndPhone(Intent intent, int phoneId) {
    626     return carrierPackageNames.get(phoneId);
    627   }
    628 
    629   @Implementation(minSdk = LOLLIPOP)
    630   @HiddenApi
    631   protected List<String> getCarrierPackageNamesForIntent(Intent intent) {
    632     return carrierPackageNames.get(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID);
    633   }
    634 
    635   /** Sets the {@code packages} for the given {@code phoneId}. */
    636   public void setCarrierPackageNamesForPhone(int phoneId, List<String> packages) {
    637     carrierPackageNames.put(phoneId, packages);
    638   }
    639 
    640   @Implementation(minSdk = P)
    641   protected int getSimCarrierId() {
    642     return simCarrierId;
    643   }
    644 
    645   /** Sets the value to be returned by {@link #getSimCarrierId()}. */
    646   public void setSimCarrierId(int simCarrierId) {
    647     this.simCarrierId = simCarrierId;
    648   }
    649 
    650   @Implementation
    651   protected String getSubscriberId() {
    652     return subscriberId;
    653   }
    654 
    655   /** Sets the value to be returned by {@link #getSubscriberId()}. */
    656   public void setSubscriberId(String subscriberId) {
    657     this.subscriberId = subscriberId;
    658   }
    659 }
    660