1package org.robolectric.shadows; 2 3import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR2; 4import static android.os.Build.VERSION_CODES.LOLLIPOP; 5 6import android.net.DhcpInfo; 7import android.net.wifi.ScanResult; 8import android.net.wifi.WifiConfiguration; 9import android.net.wifi.WifiInfo; 10import android.net.wifi.WifiManager; 11import android.util.Pair; 12import java.util.ArrayList; 13import java.util.LinkedHashMap; 14import java.util.List; 15import java.util.Map; 16import org.robolectric.Shadows; 17import org.robolectric.annotation.Implementation; 18import org.robolectric.annotation.Implements; 19import org.robolectric.util.ReflectionHelpers; 20 21/** 22 * Shadow for {@link android.net.wifi.WifiManager}. 23 */ 24@Implements(WifiManager.class) 25public class ShadowWifiManager { 26 private static float sSignalLevelInPercent = 1f; 27 private boolean accessWifiStatePermission = true; 28 private boolean wifiEnabled = true; 29 private boolean wasSaved = false; 30 private WifiInfo wifiInfo; 31 private List<ScanResult> scanResults; 32 private final Map<Integer, WifiConfiguration> networkIdToConfiguredNetworks = new LinkedHashMap<>(); 33 private Pair<Integer, Boolean> lastEnabledNetwork; 34 private DhcpInfo dhcpInfo; 35 private boolean isScanAlwaysAvailable = true; 36 37 @Implementation 38 public boolean setWifiEnabled(boolean wifiEnabled) { 39 checkAccessWifiStatePermission(); 40 this.wifiEnabled = wifiEnabled; 41 return true; 42 } 43 44 @Implementation 45 public boolean isWifiEnabled() { 46 checkAccessWifiStatePermission(); 47 return wifiEnabled; 48 } 49 50 @Implementation 51 public int getWifiState() { 52 if (isWifiEnabled()) { 53 return WifiManager.WIFI_STATE_ENABLED; 54 } else { 55 return WifiManager.WIFI_STATE_DISABLED; 56 } 57 } 58 59 @Implementation 60 public WifiInfo getConnectionInfo() { 61 checkAccessWifiStatePermission(); 62 if (wifiInfo == null) { 63 wifiInfo = ReflectionHelpers.callConstructor(WifiInfo.class); 64 } 65 return wifiInfo; 66 } 67 68 /** 69 * Sets the connection info as the provided {@link WifiInfo}. 70 */ 71 public void setConnectionInfo(WifiInfo wifiInfo) { 72 this.wifiInfo = wifiInfo; 73 } 74 75 @Implementation 76 public List<ScanResult> getScanResults() { 77 return scanResults; 78 } 79 80 @Implementation 81 public List<WifiConfiguration> getConfiguredNetworks() { 82 final ArrayList<WifiConfiguration> wifiConfigurations = new ArrayList<>(); 83 for (WifiConfiguration wifiConfiguration : networkIdToConfiguredNetworks.values()) { 84 wifiConfigurations.add(wifiConfiguration); 85 } 86 return wifiConfigurations; 87 } 88 89 @Implementation(minSdk = LOLLIPOP) 90 public List<WifiConfiguration> getPrivilegedConfiguredNetworks() { 91 return getConfiguredNetworks(); 92 } 93 94 @Implementation 95 public int addNetwork(WifiConfiguration config) { 96 int networkId = networkIdToConfiguredNetworks.size(); 97 config.networkId = -1; 98 networkIdToConfiguredNetworks.put(networkId, makeCopy(config, networkId)); 99 return networkId; 100 } 101 102 @Implementation 103 public boolean removeNetwork(int netId) { 104 networkIdToConfiguredNetworks.remove(netId); 105 return true; 106 } 107 108 @Implementation 109 public int updateNetwork(WifiConfiguration config) { 110 if (config == null || config.networkId < 0) { 111 return -1; 112 } 113 networkIdToConfiguredNetworks.put(config.networkId, makeCopy(config, config.networkId)); 114 return config.networkId; 115 } 116 117 @Implementation 118 public boolean saveConfiguration() { 119 wasSaved = true; 120 return true; 121 } 122 123 @Implementation 124 public boolean enableNetwork(int netId, boolean disableOthers) { 125 lastEnabledNetwork = new Pair<>(netId, disableOthers); 126 return true; 127 } 128 129 @Implementation 130 public WifiManager.WifiLock createWifiLock(int lockType, java.lang.String tag) { 131 return ReflectionHelpers.callConstructor(WifiManager.WifiLock.class); 132 } 133 134 @Implementation 135 public WifiManager.WifiLock createWifiLock(java.lang.String tag) { 136 return createWifiLock(WifiManager.WIFI_MODE_FULL, tag); 137 } 138 139 @Implementation 140 public static int calculateSignalLevel(int rssi, int numLevels) { 141 return (int) (sSignalLevelInPercent * (numLevels - 1)); 142 } 143 144 @Implementation 145 public boolean startScan() { 146 return true; 147 } 148 149 @Implementation 150 public DhcpInfo getDhcpInfo() { 151 return dhcpInfo; 152 } 153 154 @Implementation(minSdk = JELLY_BEAN_MR2) 155 public boolean isScanAlwaysAvailable() { 156 return isScanAlwaysAvailable; 157 } 158 159 public static void setSignalLevelInPercent(float level) { 160 if (level < 0 || level > 1) { 161 throw new IllegalArgumentException("level needs to be between 0 and 1"); 162 } 163 sSignalLevelInPercent = level; 164 } 165 166 public void setAccessWifiStatePermission(boolean accessWifiStatePermission) { 167 this.accessWifiStatePermission = accessWifiStatePermission; 168 } 169 170 public void setScanResults(List<ScanResult> scanResults) { 171 this.scanResults = scanResults; 172 } 173 174 public void setDhcpInfo(DhcpInfo dhcpInfo) { 175 this.dhcpInfo = dhcpInfo; 176 } 177 178 public Pair<Integer, Boolean> getLastEnabledNetwork() { 179 return lastEnabledNetwork; 180 } 181 182 public boolean wasConfigurationSaved() { 183 return wasSaved; 184 } 185 186 public void setIsScanAlwaysAvailable(boolean isScanAlwaysAvailable) { 187 this.isScanAlwaysAvailable = isScanAlwaysAvailable; 188 } 189 190 private void checkAccessWifiStatePermission() { 191 if (!accessWifiStatePermission) { 192 throw new SecurityException(); 193 } 194 } 195 196 private WifiConfiguration makeCopy(WifiConfiguration config, int networkId) { 197 WifiConfiguration copy = Shadows.shadowOf(config).copy(); 198 copy.networkId = networkId; 199 return copy; 200 } 201 202 @Implements(WifiManager.WifiLock.class) 203 public static class ShadowWifiLock { 204 private int refCount; 205 private boolean refCounted = true; 206 private boolean locked; 207 public static final int MAX_ACTIVE_LOCKS = 50; 208 209 @Implementation 210 public synchronized void acquire() { 211 if (refCounted) { 212 if (++refCount >= MAX_ACTIVE_LOCKS) throw new UnsupportedOperationException("Exceeded maximum number of wifi locks"); 213 } else { 214 locked = true; 215 } 216 } 217 218 @Implementation 219 public synchronized void release() { 220 if (refCounted) { 221 if (--refCount < 0) throw new RuntimeException("WifiLock under-locked"); 222 } else { 223 locked = false; 224 } 225 } 226 227 @Implementation 228 public synchronized boolean isHeld() { 229 return refCounted ? refCount > 0 : locked; 230 } 231 232 @Implementation 233 public void setReferenceCounted(boolean refCounted) { 234 this.refCounted = refCounted; 235 } 236 } 237} 238