• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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   {
resetSimStates()90     resetSimStates();
resetSimCountryIsos()91     resetSimCountryIsos();
92   }
93 
94   @Implementation
listen(PhoneStateListener listener, int flags)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
getListener()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
getEventFlags()125   public int getEventFlags() {
126     return lastEventFlags;
127   }
128 
129   /** Call state may be specified via {@link #setCallState(int)}. */
130   @Implementation
getCallState()131   protected int getCallState() {
132     return callState;
133   }
134 
135   /** Sets the current call state to the desired state and updates any listeners. */
setCallState(int callState)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    */
setCallState(int callState, String incomingPhoneNumber)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
getDeviceId()158   protected String getDeviceId() {
159     checkReadPhoneStatePermission();
160     return deviceId;
161   }
162 
setDeviceId(String newDeviceId)163   public void setDeviceId(String newDeviceId) {
164     deviceId = newDeviceId;
165   }
166 
setNetworkOperatorName(String networkOperatorName)167   public void setNetworkOperatorName(String networkOperatorName) {
168     this.networkOperatorName = networkOperatorName;
169   }
170 
171   @Implementation(minSdk = LOLLIPOP)
getImei()172   protected String getImei() {
173     checkReadPhoneStatePermission();
174     return imei;
175   }
176 
177   /** Set the IMEI returned by getImei(). */
setImei(String imei)178   public void setImei(String imei) {
179     this.imei = imei;
180   }
181 
182   @Implementation(minSdk = O)
getMeid()183   protected String getMeid() {
184     checkReadPhoneStatePermission();
185     return meid;
186   }
187 
188   /** Set the MEID returned by getMeid(). */
setMeid(String meid)189   public void setMeid(String meid) {
190     this.meid = meid;
191   }
192 
193   @Implementation
getNetworkOperatorName()194   protected String getNetworkOperatorName() {
195     return networkOperatorName;
196   }
197 
setNetworkCountryIso(String networkCountryIso)198   public void setNetworkCountryIso(String networkCountryIso) {
199     this.networkCountryIso = networkCountryIso;
200   }
201 
202   @Implementation
getNetworkCountryIso()203   protected String getNetworkCountryIso() {
204     return networkCountryIso;
205   }
206 
setNetworkOperator(String networkOperator)207   public void setNetworkOperator(String networkOperator) {
208     this.networkOperator = networkOperator;
209   }
210 
211   @Implementation
getNetworkOperator()212   protected String getNetworkOperator() {
213     return networkOperator;
214   }
215 
216   @Implementation
getSimOperator()217   protected String getSimOperator() {
218     return simOperator;
219   }
220 
setSimOperator(String simOperator)221   public void setSimOperator(String simOperator) {
222     this.simOperator = simOperator;
223   }
224 
225   @Implementation
getSimOperatorName()226   protected String getSimOperatorName() {
227     return simOperatorName;
228   }
229 
setSimOperatorName(String simOperatorName)230   public void setSimOperatorName(String simOperatorName) {
231     this.simOperatorName = simOperatorName;
232   }
233 
234   @Implementation
getSimSerialNumber()235   protected String getSimSerialNumber() {
236     checkReadPhoneStatePermission();
237     return this.simSerialNumber;
238   }
239 
240   /** sets the serial number that will be returned by {@link #getSimSerialNumber}. */
setSimSerialNumber(String simSerialNumber)241   public void setSimSerialNumber(String simSerialNumber) {
242     this.simSerialNumber = simSerialNumber;
243   }
244 
245   @Implementation
getSimCountryIso()246   protected String getSimCountryIso() {
247     return simCountryIsoMap.get(/* subId= */ 0);
248   }
249 
250   @Implementation(minSdk = N)
251   @HiddenApi
getSimCountryIso(int subId)252   protected String getSimCountryIso(int subId) {
253     return simCountryIsoMap.get(subId);
254   }
255 
setSimCountryIso(String simCountryIso)256   public void setSimCountryIso(String simCountryIso) {
257     setSimCountryIso(/* subId= */ 0, simCountryIso);
258   }
259 
260   /** Sets the {@code simCountryIso} for the given {@code subId}. */
setSimCountryIso(int subId, String simCountryIso)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. */
resetSimCountryIsos()266   public void resetSimCountryIsos() {
267     simCountryIsoMap.clear();
268     simCountryIsoMap.put(0, "");
269   }
270 
271   @Implementation
getSimState()272   protected int getSimState() {
273     return getSimState(/* slotIndex= */ 0);
274   }
275 
276   /** Sets the sim state of slot 0. */
setSimState(int simState)277   public void setSimState(int simState) {
278     setSimState(/* slotIndex= */ 0, simState);
279   }
280 
281   /** Set the sim state for the given {@code slotIndex}. */
setSimState(int slotIndex, int state)282   public void setSimState(int slotIndex, int state) {
283     simStates.put(slotIndex, state);
284   }
285 
286   @Implementation(minSdk = O)
getSimState(int slotIndex)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. */
resetSimStates()292   public void resetSimStates() {
293     simStates.clear();
294     simStates.put(0, TelephonyManager.SIM_STATE_READY);
295   }
296 
setReadPhoneStatePermission(boolean readPhoneStatePermission)297   public void setReadPhoneStatePermission(boolean readPhoneStatePermission) {
298     this.readPhoneStatePermission = readPhoneStatePermission;
299   }
300 
checkReadPhoneStatePermission()301   private void checkReadPhoneStatePermission() {
302     if (!readPhoneStatePermission) {
303       throw new SecurityException();
304     }
305   }
306 
307   @Implementation
getPhoneType()308   protected int getPhoneType() {
309     return phoneType;
310   }
311 
setPhoneType(int phoneType)312   public void setPhoneType(int phoneType) {
313     this.phoneType = phoneType;
314   }
315 
316   @Implementation
getLine1Number()317   protected String getLine1Number() {
318     return line1Number;
319   }
320 
setLine1Number(String line1Number)321   public void setLine1Number(String line1Number) {
322     this.line1Number = line1Number;
323   }
324 
325   @Implementation
getNetworkType()326   protected int getNetworkType() {
327     return networkType;
328   }
329 
setNetworkType(int networkType)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)
getVoiceNetworkType()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    */
setVoiceNetworkType(int voiceNetworkType)348   public void setVoiceNetworkType(int voiceNetworkType) {
349     this.voiceNetworkType = voiceNetworkType;
350   }
351 
352   @Implementation(minSdk = JELLY_BEAN_MR1)
getAllCellInfo()353   protected List<CellInfo> getAllCellInfo() {
354     return allCellInfo;
355   }
356 
setAllCellInfo(List<CellInfo> allCellInfo)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
getCellLocation()368   protected CellLocation getCellLocation() {
369     return this.cellLocation;
370   }
371 
setCellLocation(CellLocation cellLocation)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)
getGroupIdLevel1()381   protected String getGroupIdLevel1() {
382     return this.groupIdLevel1;
383   }
384 
setGroupIdLevel1(String groupIdLevel1)385   public void setGroupIdLevel1(String groupIdLevel1) {
386     this.groupIdLevel1 = groupIdLevel1;
387   }
388 
initListener(PhoneStateListener listener, int flags)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 
getListenersForFlags(int flags)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