1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.tv.settings.connectivity; 18 19 import android.content.BroadcastReceiver; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.content.IntentFilter; 23 import android.net.ConnectivityManager; 24 import android.net.EthernetManager; 25 import android.net.IpConfiguration; 26 import android.net.LinkAddress; 27 import android.net.LinkProperties; 28 import android.net.NetworkInfo; 29 import android.net.wifi.ScanResult; 30 import android.net.wifi.WifiConfiguration; 31 import android.net.wifi.WifiConfiguration.KeyMgmt; 32 import android.net.wifi.WifiInfo; 33 import android.net.wifi.WifiManager; 34 import android.text.TextUtils; 35 import android.util.Log; 36 import android.util.Pair; 37 38 import java.net.Inet4Address; 39 import java.net.InetAddress; 40 import java.util.ArrayList; 41 import java.util.Collections; 42 import java.util.HashMap; 43 import java.util.List; 44 45 /** 46 * Listens for changes to the current connectivity status. 47 */ 48 public class ConnectivityListener { 49 50 public interface Listener { onConnectivityChange(Intent intent)51 void onConnectivityChange(Intent intent); 52 } 53 54 public interface WifiNetworkListener { onWifiListChanged()55 void onWifiListChanged(); 56 } 57 58 private static final String TAG = "ConnectivityListener"; 59 private static final boolean DEBUG = false; 60 61 private final Context mContext; 62 private final Listener mListener; 63 private final IntentFilter mFilter; 64 private final BroadcastReceiver mReceiver; 65 private boolean mStarted; 66 67 private final ConnectivityManager mConnectivityManager; 68 private final WifiManager mWifiManager; 69 private final EthernetManager mEthernetManager; 70 private WifiNetworkListener mWifiListener; 71 private final BroadcastReceiver mWifiListReceiver = new BroadcastReceiver() { 72 @Override 73 public void onReceive(Context context, Intent intent) { 74 if (mWifiListener != null) { 75 mWifiListener.onWifiListChanged(); 76 mWifiListener = null; 77 } 78 } 79 }; 80 private final BroadcastReceiver mWifiEnabledReceiver = new BroadcastReceiver() { 81 @Override 82 public void onReceive(Context context, Intent intent) { 83 mListener.onConnectivityChange(intent); 84 } 85 }; 86 private final EthernetManager.Listener mEthernetListener = new EthernetManager.Listener() { 87 @Override 88 public void onAvailabilityChanged(boolean isAvailable) { 89 mListener.onConnectivityChange(null); 90 } 91 }; 92 93 public static class ConnectivityStatus { 94 public static final int NETWORK_NONE = 1; 95 public static final int NETWORK_WIFI_OPEN = 3; 96 public static final int NETWORK_WIFI_SECURE = 5; 97 public static final int NETWORK_ETHERNET = 7; 98 99 public int mNetworkType; 100 public String mWifiSsid; 101 public int mWifiSignalStrength; 102 isEthernetConnected()103 boolean isEthernetConnected() { return mNetworkType == NETWORK_ETHERNET; } isWifiConnected()104 boolean isWifiConnected() { 105 return mNetworkType == NETWORK_WIFI_OPEN || mNetworkType == NETWORK_WIFI_SECURE; 106 } 107 108 @Override toString()109 public String toString() { 110 return new StringBuilder() 111 .append("mNetworkType ").append(mNetworkType) 112 .append(" miWifiSsid ").append(mWifiSsid) 113 .append(" mWifiSignalStrength ").append(mWifiSignalStrength) 114 .toString(); 115 } 116 } 117 118 private final ConnectivityStatus mConnectivityStatus = new ConnectivityStatus(); 119 ConnectivityListener(Context context, Listener listener)120 public ConnectivityListener(Context context, Listener listener) { 121 mContext = context; 122 mConnectivityManager = (ConnectivityManager) mContext.getSystemService( 123 Context.CONNECTIVITY_SERVICE); 124 mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); 125 mEthernetManager = (EthernetManager) mContext.getSystemService(Context.ETHERNET_SERVICE); 126 mListener = listener; 127 mFilter = new IntentFilter(); 128 mFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); 129 mFilter.addAction(ConnectivityManager.INET_CONDITION_ACTION); 130 mFilter.addAction(WifiManager.RSSI_CHANGED_ACTION); 131 mReceiver = new BroadcastReceiver() { 132 @Override 133 public void onReceive(Context context, Intent intent) { 134 if (DEBUG) { 135 Log.d(TAG, "Connectivity change!"); 136 } 137 if (updateConnectivityStatus()) { 138 mListener.onConnectivityChange(intent); 139 } 140 } 141 }; 142 } 143 144 /** 145 * Starts {@link ConnectivityListener}. 146 * This should be called only from main thread. 147 */ start()148 public void start() { 149 if (!mStarted) { 150 mStarted = true; 151 updateConnectivityStatus(); 152 mContext.registerReceiver(mReceiver, mFilter); 153 mContext.registerReceiver(mWifiListReceiver, new IntentFilter( 154 WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)); 155 mContext.registerReceiver(mWifiEnabledReceiver, new IntentFilter( 156 WifiManager.WIFI_STATE_CHANGED_ACTION)); 157 mEthernetManager.addListener(mEthernetListener); 158 } 159 } 160 161 /** 162 * Stops {@link ConnectivityListener}. 163 * This should be called only from main thread. 164 */ stop()165 public void stop() { 166 if (mStarted) { 167 mStarted = false; 168 mContext.unregisterReceiver(mReceiver); 169 mContext.unregisterReceiver(mWifiListReceiver); 170 mContext.unregisterReceiver(mWifiEnabledReceiver); 171 mWifiListener = null; 172 mEthernetManager.removeListener(mEthernetListener); 173 } 174 } 175 176 /** 177 * Listener is notified when results are available via onWifiListChanged. 178 * Listener should call {@link getAvailableNetworks} to retrieve results. 179 */ scanWifiAccessPoints(WifiNetworkListener callbackListener)180 public void scanWifiAccessPoints(WifiNetworkListener callbackListener) { 181 if (DEBUG) Log.d(TAG, "scanning for wifi access points"); 182 mWifiListener = callbackListener; 183 mWifiManager.startScan(); 184 } 185 getConnectivityStatus()186 public ConnectivityStatus getConnectivityStatus() { 187 return mConnectivityStatus; 188 } 189 getWifiIpAddress()190 public String getWifiIpAddress() { 191 if (mConnectivityStatus.isWifiConnected()) { 192 WifiInfo wifiInfo = mWifiManager.getConnectionInfo(); 193 int ip = wifiInfo.getIpAddress(); 194 return String.format("%d.%d.%d.%d", (ip & 0xff), (ip >> 8 & 0xff), 195 (ip >> 16 & 0xff), (ip >> 24 & 0xff)); 196 } else { 197 return ""; 198 } 199 } 200 201 /** 202 * Return the MAC address of the currently connected Wifi AP. 203 */ getWifiMacAddress()204 public String getWifiMacAddress() { 205 if (mConnectivityStatus.isWifiConnected()) { 206 WifiInfo wifiInfo = mWifiManager.getConnectionInfo(); 207 return wifiInfo.getMacAddress(); 208 } else { 209 return ""; 210 } 211 } 212 213 /** 214 * Return whether Ethernet port is available. 215 */ isEthernetAvailable()216 public boolean isEthernetAvailable() { 217 if (mConnectivityManager.isNetworkSupported(ConnectivityManager.TYPE_ETHERNET)) { 218 return mEthernetManager.isAvailable(); 219 } 220 221 return false; 222 } 223 getEthernetMacAddress()224 public String getEthernetMacAddress() { 225 NetworkInfo networkInfo = mConnectivityManager.getActiveNetworkInfo(); 226 if (networkInfo == null ||networkInfo.getType() != ConnectivityManager.TYPE_ETHERNET) { 227 return ""; 228 } else { 229 return networkInfo.getExtraInfo(); 230 } 231 } 232 getEthernetIpAddress()233 public String getEthernetIpAddress() { 234 LinkProperties linkProperties = 235 mConnectivityManager.getLinkProperties(ConnectivityManager.TYPE_ETHERNET); 236 237 for (LinkAddress linkAddress: linkProperties.getAllLinkAddresses()) { 238 InetAddress address = linkAddress.getAddress(); 239 if (address instanceof Inet4Address) { 240 return address.getHostAddress(); 241 } 242 } 243 244 // IPv6 address will not be shown like WifiInfo internally does. 245 return ""; 246 } 247 getWifiSignalStrength(int maxLevel)248 public int getWifiSignalStrength(int maxLevel) { 249 WifiInfo wifiInfo = mWifiManager.getConnectionInfo(); 250 return WifiManager.calculateSignalLevel(wifiInfo.getRssi(), maxLevel); 251 } 252 forgetWifiNetwork()253 public void forgetWifiNetwork() { 254 int networkId = getWifiNetworkId(); 255 if (networkId != -1) { 256 mWifiManager.forget(networkId, null); 257 } 258 } 259 getWifiNetworkId()260 public int getWifiNetworkId() { 261 WifiInfo wifiInfo = mWifiManager.getConnectionInfo(); 262 if (wifiInfo != null) { 263 return wifiInfo.getNetworkId(); 264 } else { 265 return -1; 266 } 267 } 268 getWifiConfiguration()269 public WifiConfiguration getWifiConfiguration() { 270 WifiInfo wifiInfo = mWifiManager.getConnectionInfo(); 271 if (wifiInfo != null) { 272 int networkId = wifiInfo.getNetworkId(); 273 List<WifiConfiguration> configuredNetworks = mWifiManager.getConfiguredNetworks(); 274 if (configuredNetworks != null) { 275 for (WifiConfiguration configuredNetwork : configuredNetworks) { 276 if (configuredNetwork.networkId == networkId) { 277 return configuredNetwork; 278 } 279 } 280 } 281 } 282 return null; 283 } 284 285 /** 286 * Return a list of wifi networks. Ensure that if a wifi network is connected that it appears 287 * as the first item on the list. 288 */ getAvailableNetworks()289 public List<ScanResult> getAvailableNetworks() { 290 if (DEBUG) Log.d(TAG, "getAvailableNetworks"); 291 WifiInfo connectedWifiInfo = mWifiManager.getConnectionInfo(); 292 String currentConnectedSSID = connectedWifiInfo == null ? "" : connectedWifiInfo.getSSID(); 293 currentConnectedSSID = WifiInfo.removeDoubleQuotes(currentConnectedSSID); 294 WifiSecurity currentConnectedSecurity = WifiConfigHelper.getCurrentConnectionSecurity( 295 mWifiManager, connectedWifiInfo); 296 297 // TODO : Refactor with similar code in SelectFromListWizard 298 final List<ScanResult> results = mWifiManager.getScanResults(); 299 300 if (results.size() == 0) { 301 Log.w(TAG, "No results found! Initiate scan..."); 302 mWifiManager.startScan(); 303 } 304 305 final HashMap<Pair<String, WifiSecurity>, ScanResult> consolidatedScanResults = 306 new HashMap<Pair<String, WifiSecurity>, ScanResult>(); 307 HashMap<Pair<String, WifiSecurity>, Boolean> specialNetworks = new HashMap< 308 Pair<String, WifiSecurity>, Boolean>(); 309 for (ScanResult result : results) { 310 if (TextUtils.isEmpty(result.SSID)) { 311 continue; 312 } 313 314 Pair<String, WifiSecurity> key = Pair.create( 315 result.SSID, WifiSecurity.getSecurity(result)); 316 ScanResult existing = consolidatedScanResults.get(key); 317 318 if (WifiConfigHelper.areSameNetwork(mWifiManager, result, connectedWifiInfo)) { 319 // The currently connected network should always be included. 320 consolidatedScanResults.put(key, result); 321 specialNetworks.put(key, true); 322 } else { 323 if (existing == null || 324 (!specialNetworks.containsKey(key) && existing.level < result.level)) { 325 consolidatedScanResults.put(key, result); 326 } 327 } 328 } 329 330 ArrayList<ScanResult> networkList = new ArrayList<ScanResult>( 331 consolidatedScanResults.size()); 332 networkList.addAll(consolidatedScanResults.values()); 333 ScanResultComparator comparator = connectedWifiInfo == null ? new ScanResultComparator() : 334 new ScanResultComparator(currentConnectedSSID, currentConnectedSecurity); 335 Collections.sort(networkList, comparator); 336 return networkList; 337 } 338 getIpConfiguration()339 public IpConfiguration getIpConfiguration() { 340 return mEthernetManager.getConfiguration(); 341 } 342 isSecureWifi(WifiInfo wifiInfo)343 private boolean isSecureWifi(WifiInfo wifiInfo) { 344 if (wifiInfo == null) 345 return false; 346 int networkId = wifiInfo.getNetworkId(); 347 List<WifiConfiguration> configuredNetworks = mWifiManager.getConfiguredNetworks(); 348 if (configuredNetworks != null) { 349 for (WifiConfiguration configuredNetwork : configuredNetworks) { 350 if (configuredNetwork.networkId == networkId) { 351 return configuredNetwork.allowedKeyManagement.get(KeyMgmt.WPA_PSK) || 352 configuredNetwork.allowedKeyManagement.get(KeyMgmt.WPA_EAP) || 353 configuredNetwork.allowedKeyManagement.get(KeyMgmt.IEEE8021X); 354 } 355 } 356 } 357 return false; 358 } 359 isWifiEnabled()360 public boolean isWifiEnabled() { 361 return mWifiManager.isWifiEnabled(); 362 } 363 setWifiEnabled(boolean enable)364 public void setWifiEnabled(boolean enable) { 365 mWifiManager.setWifiEnabled(enable); 366 } 367 setNetworkType(int networkType)368 private boolean setNetworkType(int networkType) { 369 boolean hasChanged = mConnectivityStatus.mNetworkType != networkType; 370 mConnectivityStatus.mNetworkType = networkType; 371 return hasChanged; 372 } 373 updateConnectivityStatus()374 private boolean updateConnectivityStatus() { 375 NetworkInfo networkInfo = mConnectivityManager.getActiveNetworkInfo(); 376 if (networkInfo == null) { 377 return setNetworkType(ConnectivityStatus.NETWORK_NONE); 378 } else { 379 switch (networkInfo.getType()) { 380 case ConnectivityManager.TYPE_WIFI: { 381 boolean hasChanged; 382 383 // Determine if this is an open or secure wifi connection. 384 WifiInfo wifiInfo = mWifiManager.getConnectionInfo(); 385 if (isSecureWifi(wifiInfo)) { 386 hasChanged = setNetworkType(ConnectivityStatus.NETWORK_WIFI_SECURE); 387 } else { 388 hasChanged = setNetworkType(ConnectivityStatus.NETWORK_WIFI_OPEN); 389 } 390 391 // Find the SSID of network. 392 String ssid = null; 393 if (wifiInfo != null) { 394 ssid = wifiInfo.getSSID(); 395 if (ssid != null) { 396 ssid = WifiInfo.removeDoubleQuotes(ssid); 397 } 398 } 399 if (!TextUtils.equals(mConnectivityStatus.mWifiSsid, ssid)) { 400 hasChanged = true; 401 mConnectivityStatus.mWifiSsid = ssid; 402 } 403 404 // Calculate the signal strength. 405 int signalStrength; 406 if (wifiInfo != null) { 407 // Calculate the signal strength between 0 and 3. 408 signalStrength = WifiManager.calculateSignalLevel(wifiInfo.getRssi(), 4); 409 } else { 410 signalStrength = 0; 411 } 412 if (mConnectivityStatus.mWifiSignalStrength != signalStrength) { 413 hasChanged = true; 414 mConnectivityStatus.mWifiSignalStrength = signalStrength; 415 } 416 return hasChanged; 417 } 418 419 case ConnectivityManager.TYPE_ETHERNET: 420 return setNetworkType(ConnectivityStatus.NETWORK_ETHERNET); 421 422 default: 423 return setNetworkType(ConnectivityStatus.NETWORK_NONE); 424 } 425 } 426 } 427 } 428