• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.robolectric.shadows;
2 
3 import static android.os.Build.VERSION_CODES.LOLLIPOP;
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;
7 import static android.os.Build.VERSION_CODES.S;
8 import static org.robolectric.RuntimeEnvironment.getApiLevel;
9 import static org.robolectric.Shadows.shadowOf;
10 
11 import android.app.PendingIntent;
12 import android.net.ConnectivityManager;
13 import android.net.ConnectivityManager.OnNetworkActiveListener;
14 import android.net.LinkProperties;
15 import android.net.Network;
16 import android.net.NetworkCapabilities;
17 import android.net.NetworkInfo;
18 import android.net.NetworkRequest;
19 import android.net.ProxyInfo;
20 import android.os.Handler;
21 import java.util.HashMap;
22 import java.util.HashSet;
23 import java.util.Map;
24 import java.util.Set;
25 import org.robolectric.annotation.HiddenApi;
26 import org.robolectric.annotation.Implementation;
27 import org.robolectric.annotation.Implements;
28 import org.robolectric.shadow.api.Shadow;
29 
30 @Implements(ConnectivityManager.class)
31 public class ShadowConnectivityManager {
32 
33   // Package-private for tests.
34   static final int NET_ID_WIFI = ConnectivityManager.TYPE_WIFI;
35   static final int NET_ID_MOBILE = ConnectivityManager.TYPE_MOBILE;
36 
37   private NetworkInfo activeNetworkInfo;
38   private boolean backgroundDataSetting;
39   private int restrictBackgroundStatus = ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED;
40   private int networkPreference = ConnectivityManager.DEFAULT_NETWORK_PREFERENCE;
41   private final Map<Integer, NetworkInfo> networkTypeToNetworkInfo = new HashMap<>();
42 
43   private HashSet<ConnectivityManager.NetworkCallback> networkCallbacks = new HashSet<>();
44   private final HashSet<PendingIntent> networkCallbackPendingIntents = new HashSet<>();
45 
46   private final Map<Integer, Network> netIdToNetwork = new HashMap<>();
47   private final Map<Integer, NetworkInfo> netIdToNetworkInfo = new HashMap<>();
48   private Network processBoundNetwork;
49   private boolean defaultNetworkActive;
50   private HashSet<ConnectivityManager.OnNetworkActiveListener> onNetworkActiveListeners =
51       new HashSet<>();
52   private Map<Network, Boolean> reportedNetworkConnectivity = new HashMap<>();
53   private Map<Network, NetworkCapabilities> networkCapabilitiesMap = new HashMap<>();
54   private String captivePortalServerUrl = "http://10.0.0.2";
55   private final Map<Network, LinkProperties> linkPropertiesMap = new HashMap<>();
56   private final Map<Network, ProxyInfo> proxyInfoMap = new HashMap<>();
57 
ShadowConnectivityManager()58   public ShadowConnectivityManager() {
59     NetworkInfo wifi = ShadowNetworkInfo.newInstance(NetworkInfo.DetailedState.DISCONNECTED,
60         ConnectivityManager.TYPE_WIFI, 0, true, false);
61     networkTypeToNetworkInfo.put(ConnectivityManager.TYPE_WIFI, wifi);
62 
63     NetworkInfo mobile = ShadowNetworkInfo.newInstance(NetworkInfo.DetailedState.CONNECTED,
64         ConnectivityManager.TYPE_MOBILE, ConnectivityManager.TYPE_MOBILE_MMS, true, true);
65     networkTypeToNetworkInfo.put(ConnectivityManager.TYPE_MOBILE, mobile);
66 
67     this.activeNetworkInfo = mobile;
68 
69     if (getApiLevel() >= LOLLIPOP) {
70       netIdToNetwork.put(NET_ID_WIFI, ShadowNetwork.newInstance(NET_ID_WIFI));
71       netIdToNetwork.put(NET_ID_MOBILE, ShadowNetwork.newInstance(NET_ID_MOBILE));
72       netIdToNetworkInfo.put(NET_ID_WIFI, wifi);
73       netIdToNetworkInfo.put(NET_ID_MOBILE, mobile);
74 
75       NetworkCapabilities wifiNetworkCapabilities = ShadowNetworkCapabilities.newInstance();
76       shadowOf(wifiNetworkCapabilities).addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
77       NetworkCapabilities mobileNetworkCapabilities = ShadowNetworkCapabilities.newInstance();
78       shadowOf(mobileNetworkCapabilities).addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
79 
80       networkCapabilitiesMap.put(netIdToNetwork.get(NET_ID_WIFI), wifiNetworkCapabilities);
81       networkCapabilitiesMap.put(netIdToNetwork.get(NET_ID_MOBILE), mobileNetworkCapabilities);
82     }
83     defaultNetworkActive = true;
84   }
85 
getNetworkCallbacks()86   public Set<ConnectivityManager.NetworkCallback> getNetworkCallbacks() {
87     return networkCallbacks;
88   }
89 
getNetworkCallbackPendingIntents()90   public Set<PendingIntent> getNetworkCallbackPendingIntents() {
91     return networkCallbackPendingIntents;
92   }
93 
94   /**
95    * @return networks and their connectivity status which was reported with {@link
96    *     #reportNetworkConnectivity}.
97    */
getReportedNetworkConnectivity()98   public Map<Network, Boolean> getReportedNetworkConnectivity() {
99     return new HashMap<>(reportedNetworkConnectivity);
100   }
101 
102   @Implementation
registerNetworkCallback( NetworkRequest request, ConnectivityManager.NetworkCallback networkCallback)103   protected void registerNetworkCallback(
104       NetworkRequest request, ConnectivityManager.NetworkCallback networkCallback) {
105     registerNetworkCallback(request, networkCallback, null);
106   }
107 
108   @Implementation(minSdk = O)
registerNetworkCallback( NetworkRequest request, ConnectivityManager.NetworkCallback networkCallback, Handler handler)109   protected void registerNetworkCallback(
110       NetworkRequest request,
111       ConnectivityManager.NetworkCallback networkCallback,
112       Handler handler) {
113     networkCallbacks.add(networkCallback);
114   }
115 
116   @Implementation(minSdk = M)
registerNetworkCallback(NetworkRequest request, PendingIntent pendingIntent)117   protected void registerNetworkCallback(NetworkRequest request, PendingIntent pendingIntent) {
118     networkCallbackPendingIntents.add(pendingIntent);
119   }
120 
121   @Implementation
requestNetwork( NetworkRequest request, ConnectivityManager.NetworkCallback networkCallback)122   protected void requestNetwork(
123       NetworkRequest request, ConnectivityManager.NetworkCallback networkCallback) {
124     registerNetworkCallback(request, networkCallback);
125   }
126 
127   @Implementation(minSdk = O)
requestNetwork( NetworkRequest request, ConnectivityManager.NetworkCallback networkCallback, int timeoutMs)128   protected void requestNetwork(
129       NetworkRequest request, ConnectivityManager.NetworkCallback networkCallback, int timeoutMs) {
130     registerNetworkCallback(request, networkCallback);
131   }
132 
133   @Implementation(minSdk = O)
requestNetwork( NetworkRequest request, ConnectivityManager.NetworkCallback networkCallback, Handler handler)134   protected void requestNetwork(
135       NetworkRequest request,
136       ConnectivityManager.NetworkCallback networkCallback,
137       Handler handler) {
138     registerNetworkCallback(request, networkCallback);
139   }
140 
141   @Implementation(minSdk = O)
requestNetwork( NetworkRequest request, ConnectivityManager.NetworkCallback networkCallback, Handler handler, int timeoutMs)142   protected void requestNetwork(
143       NetworkRequest request,
144       ConnectivityManager.NetworkCallback networkCallback,
145       Handler handler,
146       int timeoutMs) {
147     registerNetworkCallback(request, networkCallback);
148   }
149 
150   @Implementation(minSdk = N)
registerDefaultNetworkCallback( ConnectivityManager.NetworkCallback networkCallback)151   protected void registerDefaultNetworkCallback(
152       ConnectivityManager.NetworkCallback networkCallback) {
153     networkCallbacks.add(networkCallback);
154   }
155 
156   @Implementation(minSdk = O)
registerDefaultNetworkCallback( ConnectivityManager.NetworkCallback networkCallback, Handler handler)157   protected void registerDefaultNetworkCallback(
158       ConnectivityManager.NetworkCallback networkCallback, Handler handler) {
159     networkCallbacks.add(networkCallback);
160   }
161 
162   @Implementation(minSdk = S)
registerBestMatchingNetworkCallback( NetworkRequest request, ConnectivityManager.NetworkCallback networkCallback, Handler handler)163   protected void registerBestMatchingNetworkCallback(
164       NetworkRequest request,
165       ConnectivityManager.NetworkCallback networkCallback,
166       Handler handler) {
167     networkCallbacks.add(networkCallback);
168   }
169 
170   @Implementation
unregisterNetworkCallback(ConnectivityManager.NetworkCallback networkCallback)171   protected void unregisterNetworkCallback(ConnectivityManager.NetworkCallback networkCallback) {
172     if (networkCallback == null) {
173       throw new IllegalArgumentException("Invalid NetworkCallback");
174     }
175     if (networkCallbacks.contains(networkCallback)) {
176       networkCallbacks.remove(networkCallback);
177     }
178   }
179 
180   @Implementation(minSdk = M)
unregisterNetworkCallback(PendingIntent pendingIntent)181   protected void unregisterNetworkCallback(PendingIntent pendingIntent) {
182     if (pendingIntent == null) {
183       throw new IllegalArgumentException("Invalid NetworkCallback");
184     }
185     if (networkCallbackPendingIntents.contains(pendingIntent)) {
186       networkCallbackPendingIntents.remove(pendingIntent);
187     }
188   }
189 
190   @Implementation
getActiveNetworkInfo()191   protected NetworkInfo getActiveNetworkInfo() {
192     return activeNetworkInfo;
193   }
194 
195   /**
196    * @see #setActiveNetworkInfo(NetworkInfo)
197    * @see #setNetworkInfo(int, NetworkInfo)
198    */
199   @Implementation(minSdk = M)
getActiveNetwork()200   protected Network getActiveNetwork() {
201     if (defaultNetworkActive) {
202       return netIdToNetwork.get(getActiveNetworkInfo().getType());
203     }
204     return null;
205   }
206 
207   /**
208    * @see #setActiveNetworkInfo(NetworkInfo)
209    * @see #setNetworkInfo(int, NetworkInfo)
210    */
211   @Implementation
getAllNetworkInfo()212   protected NetworkInfo[] getAllNetworkInfo() {
213     // todo(xian): is `defaultNetworkActive` really relevant here?
214     if (defaultNetworkActive) {
215       return networkTypeToNetworkInfo
216           .values()
217           .toArray(new NetworkInfo[networkTypeToNetworkInfo.size()]);
218     }
219     return null;
220   }
221 
222   @Implementation
getNetworkInfo(int networkType)223   protected NetworkInfo getNetworkInfo(int networkType) {
224     return networkTypeToNetworkInfo.get(networkType);
225   }
226 
227   @Implementation
getNetworkInfo(Network network)228   protected NetworkInfo getNetworkInfo(Network network) {
229     if (network == null) {
230       return null;
231     }
232     ShadowNetwork shadowNetwork = Shadow.extract(network);
233     return netIdToNetworkInfo.get(shadowNetwork.getNetId());
234   }
235 
236   @Implementation
getAllNetworks()237   protected Network[] getAllNetworks() {
238     return netIdToNetwork.values().toArray(new Network[netIdToNetwork.size()]);
239   }
240 
241   @Implementation
getBackgroundDataSetting()242   protected boolean getBackgroundDataSetting() {
243     return backgroundDataSetting;
244   }
245 
246   @Implementation
setNetworkPreference(int preference)247   protected void setNetworkPreference(int preference) {
248     networkPreference = preference;
249   }
250 
251   @Implementation
getNetworkPreference()252   protected int getNetworkPreference() {
253     return networkPreference;
254   }
255 
256   /**
257    * Counts {@link ConnectivityManager#TYPE_MOBILE} networks as metered. Other types will be
258    * considered unmetered.
259    *
260    * @return true if the active network is metered, otherwise false.
261    * @see #setActiveNetworkInfo(NetworkInfo)
262    * @see #setDefaultNetworkActive(boolean)
263    */
264   @Implementation
isActiveNetworkMetered()265   protected boolean isActiveNetworkMetered() {
266     if (defaultNetworkActive && activeNetworkInfo != null) {
267       return activeNetworkInfo.getType() == ConnectivityManager.TYPE_MOBILE;
268     } else {
269       return false;
270     }
271   }
272 
273   @Implementation(minSdk = M)
bindProcessToNetwork(Network network)274   protected boolean bindProcessToNetwork(Network network) {
275     processBoundNetwork = network;
276     return true;
277   }
278 
279   @Implementation(minSdk = M)
getBoundNetworkForProcess()280   protected Network getBoundNetworkForProcess() {
281     return processBoundNetwork;
282   }
283 
setNetworkInfo(int networkType, NetworkInfo networkInfo)284   public void setNetworkInfo(int networkType, NetworkInfo networkInfo) {
285     networkTypeToNetworkInfo.put(networkType, networkInfo);
286   }
287 
288   /**
289    * Returns the captive portal URL previously set with {@link #setCaptivePortalServerUrl}.
290    */
291   @Implementation(minSdk = N)
getCaptivePortalServerUrl()292   protected String getCaptivePortalServerUrl() {
293     return captivePortalServerUrl;
294   }
295 
296   /**
297    * Sets the captive portal URL, which will be returned in {@link #getCaptivePortalServerUrl}.
298    *
299    * @param captivePortalServerUrl the url of captive portal.
300    */
setCaptivePortalServerUrl(String captivePortalServerUrl)301   public void setCaptivePortalServerUrl(String captivePortalServerUrl) {
302     this.captivePortalServerUrl = captivePortalServerUrl;
303   }
304 
305   @HiddenApi @Implementation
setBackgroundDataSetting(boolean b)306   public void setBackgroundDataSetting(boolean b) {
307     backgroundDataSetting = b;
308   }
309 
setActiveNetworkInfo(NetworkInfo info)310   public void setActiveNetworkInfo(NetworkInfo info) {
311     if (getApiLevel() >= LOLLIPOP) {
312       activeNetworkInfo = info;
313       if (info != null) {
314         networkTypeToNetworkInfo.put(info.getType(), info);
315         netIdToNetwork.put(info.getType(), ShadowNetwork.newInstance(info.getType()));
316         netIdToNetworkInfo.put(info.getType(), info);
317       } else {
318         networkTypeToNetworkInfo.clear();
319         netIdToNetwork.clear();
320       }
321     } else {
322       activeNetworkInfo = info;
323       if (info != null) {
324         networkTypeToNetworkInfo.put(info.getType(), info);
325       } else {
326         networkTypeToNetworkInfo.clear();
327       }
328     }
329   }
330 
331   /**
332    * Adds new {@code network} to the list of all {@link android.net.Network}s.
333    *
334    * @param network The network.
335    * @param networkInfo The network info paired with the {@link android.net.Network}.
336    */
addNetwork(Network network, NetworkInfo networkInfo)337   public void addNetwork(Network network, NetworkInfo networkInfo) {
338     ShadowNetwork shadowNetwork = Shadow.extract(network);
339     int netId = shadowNetwork.getNetId();
340     netIdToNetwork.put(netId, network);
341     netIdToNetworkInfo.put(netId, networkInfo);
342   }
343 
344   /**
345    * Removes the {@code network} from the list of all {@link android.net.Network}s.
346    * @param network The network.
347    */
removeNetwork(Network network)348   public void removeNetwork(Network network) {
349     ShadowNetwork shadowNetwork = Shadow.extract(network);
350     int netId = shadowNetwork.getNetId();
351     netIdToNetwork.remove(netId);
352     netIdToNetworkInfo.remove(netId);
353   }
354 
355   /**
356    * Clears the list of all {@link android.net.Network}s.
357    */
clearAllNetworks()358   public void clearAllNetworks() {
359     netIdToNetwork.clear();
360     netIdToNetworkInfo.clear();
361   }
362 
363   /**
364    * Sets the active state of the default network.
365    *
366    * By default this is true and affects the result of {@link
367    * ConnectivityManager#isActiveNetworkMetered()}, {@link
368    * ConnectivityManager#isDefaultNetworkActive()}, {@link ConnectivityManager#getActiveNetwork()}
369    * and {@link ConnectivityManager#getAllNetworkInfo()}.
370    *
371    * Calling this method with {@code true} after any listeners have been registered with {@link
372    * ConnectivityManager#addDefaultNetworkActiveListener(OnNetworkActiveListener)} will result in
373    * those listeners being fired.
374    *
375    * @param isActive The active state of the default network.
376    */
setDefaultNetworkActive(boolean isActive)377   public void setDefaultNetworkActive(boolean isActive) {
378     defaultNetworkActive = isActive;
379     if (defaultNetworkActive) {
380       for (ConnectivityManager.OnNetworkActiveListener l : onNetworkActiveListeners) {
381         if (l != null) {
382           l.onNetworkActive();
383         }
384       }
385     }
386   }
387 
388   /**
389    * @return true by default, or the value specifed via {@link #setDefaultNetworkActive(boolean)}
390    * @see #setDefaultNetworkActive(boolean)
391    */
392   @Implementation
isDefaultNetworkActive()393   protected boolean isDefaultNetworkActive() {
394     return defaultNetworkActive;
395   }
396 
397   @Implementation
addDefaultNetworkActiveListener( final ConnectivityManager.OnNetworkActiveListener l)398   protected void addDefaultNetworkActiveListener(
399       final ConnectivityManager.OnNetworkActiveListener l) {
400     onNetworkActiveListeners.add(l);
401   }
402 
403   @Implementation
removeDefaultNetworkActiveListener(ConnectivityManager.OnNetworkActiveListener l)404   protected void removeDefaultNetworkActiveListener(ConnectivityManager.OnNetworkActiveListener l) {
405     if (l == null) {
406       throw new IllegalArgumentException("Invalid OnNetworkActiveListener");
407     }
408     if (onNetworkActiveListeners.contains(l)) {
409       onNetworkActiveListeners.remove(l);
410     }
411   }
412 
413   @Implementation(minSdk = M)
reportNetworkConnectivity(Network network, boolean hasConnectivity)414   protected void reportNetworkConnectivity(Network network, boolean hasConnectivity) {
415     reportedNetworkConnectivity.put(network, hasConnectivity);
416   }
417 
418   /**
419    * Gets the network capabilities of a given {@link Network}.
420    *
421    * @param network The {@link Network} object identifying the network in question.
422    * @return The {@link android.net.NetworkCapabilities} for the network.
423    * @see #setNetworkCapabilities(Network, NetworkCapabilities)
424    */
425   @Implementation
getNetworkCapabilities(Network network)426   protected NetworkCapabilities getNetworkCapabilities(Network network) {
427     return networkCapabilitiesMap.get(network);
428   }
429 
430   /**
431    * Sets network capability and affects the result of {@link
432    * ConnectivityManager#getNetworkCapabilities(Network)}
433    *
434    * @param network The {@link Network} object identifying the network in question.
435    * @param networkCapabilities The {@link android.net.NetworkCapabilities} for the network.
436    */
setNetworkCapabilities(Network network, NetworkCapabilities networkCapabilities)437   public void setNetworkCapabilities(Network network, NetworkCapabilities networkCapabilities) {
438     networkCapabilitiesMap.put(network, networkCapabilities);
439   }
440 
441   /**
442    * Sets the value for enabling/disabling airplane mode
443    *
444    * @param enable new status for airplane mode
445    */
446   @Implementation
setAirplaneMode(boolean enable)447   protected void setAirplaneMode(boolean enable) {
448     ShadowSettings.setAirplaneMode(enable);
449   }
450 
451   /**
452    * @see #setLinkProperties(Network, LinkProperties)
453    */
454   @Implementation
getLinkProperties(Network network)455   protected LinkProperties getLinkProperties(Network network) {
456     return linkPropertiesMap.get(network);
457   }
458 
459   /**
460    * Sets the LinkProperties for the given Network.
461    *
462    * <p>A LinkProperties can be constructed by {@code
463    * org.robolectric.util.ReflectionHelpers.callConstructor} in tests.
464    */
setLinkProperties(Network network, LinkProperties linkProperties)465   public void setLinkProperties(Network network, LinkProperties linkProperties) {
466     linkPropertiesMap.put(network, linkProperties);
467   }
468 
469   /**
470    * Gets the RESTRICT_BACKGROUND_STATUS value. Default value is 1
471    * (RESTRICT_BACKGROUND_STATUS_DISABLED).
472    */
473   @Implementation(minSdk = N)
getRestrictBackgroundStatus()474   protected int getRestrictBackgroundStatus() {
475     return restrictBackgroundStatus;
476   }
477 
478   /** Sets the next return value for {@link ConnectivityManager#getRestrictBackgroundStatus()}. */
setRestrictBackgroundStatus(int status)479   public void setRestrictBackgroundStatus(int status) {
480     if (status <= 0 || status >= 4) {
481       throw new IllegalArgumentException("Invalid RESTRICT_BACKGROUND_STATUS value.");
482     }
483     restrictBackgroundStatus = status;
484   }
485 
486   /**
487    * Sets a proxy for a given {@link Network}.
488    *
489    * @param network The network.
490    * @param proxyInfo The proxy info.
491    */
setProxyForNetwork(Network network, ProxyInfo proxyInfo)492   public void setProxyForNetwork(Network network, ProxyInfo proxyInfo) {
493     proxyInfoMap.put(network, proxyInfo);
494   }
495 
496   /**
497    * Returns a proxy for a given {@link Network}.
498    *
499    * <p>In order {@link ConnectivityManager#getDefaultProxy()} to work the default network should be
500    * set using {@link ConnectivityManager#bindProcessToNetwork(Network)}.
501    */
502   @Implementation(minSdk = M)
getProxyForNetwork(Network network)503   protected ProxyInfo getProxyForNetwork(Network network) {
504     return proxyInfoMap.get(network);
505   }
506 }
507