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.annotation.SuppressLint; 20 import android.content.BroadcastReceiver; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.content.IntentFilter; 24 import android.net.ConnectivityManager; 25 import android.net.EthernetManager; 26 import android.net.LinkAddress; 27 import android.net.LinkProperties; 28 import android.net.Network; 29 import android.net.NetworkInfo; 30 import android.net.wifi.WifiConfiguration; 31 import android.net.wifi.WifiInfo; 32 import android.net.wifi.WifiManager; 33 import android.telephony.PhoneStateListener; 34 import android.telephony.SignalStrength; 35 import android.telephony.TelephonyManager; 36 import android.text.TextUtils; 37 import android.util.Log; 38 39 import androidx.annotation.UiThread; 40 41 import com.android.settingslib.core.lifecycle.Lifecycle; 42 import com.android.settingslib.core.lifecycle.LifecycleObserver; 43 import com.android.settingslib.core.lifecycle.events.OnStart; 44 import com.android.settingslib.core.lifecycle.events.OnStop; 45 import com.android.settingslib.wifi.AccessPoint; 46 import com.android.settingslib.wifi.WifiTracker; 47 48 import java.util.ArrayList; 49 import java.util.List; 50 51 /** 52 * Listens for changes to the current connectivity status. 53 */ 54 public class ConnectivityListener implements WifiTracker.WifiListener, LifecycleObserver, OnStart, 55 OnStop { 56 57 private static final String TAG = "ConnectivityListener"; 58 59 private final Context mContext; 60 private final Listener mListener; 61 private boolean mStarted; 62 63 private WifiTracker mWifiTracker; 64 65 private final ConnectivityManager mConnectivityManager; 66 private final WifiManager mWifiManager; 67 private final EthernetManager mEthernetManager; 68 private WifiNetworkListener mWifiListener; 69 private final BroadcastReceiver mNetworkReceiver = new BroadcastReceiver() { 70 @Override 71 public void onReceive(Context context, Intent intent) { 72 updateConnectivityStatus(); 73 if (mListener != null) { 74 mListener.onConnectivityChange(); 75 } 76 } 77 }; 78 private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() { 79 @Override 80 public void onSignalStrengthsChanged(SignalStrength signalStrength) { 81 mCellSignalStrength = signalStrength; 82 mListener.onConnectivityChange(); 83 } 84 }; 85 86 private SignalStrength mCellSignalStrength; 87 private int mNetworkType; 88 private String mWifiSsid; 89 private int mWifiSignalStrength; 90 91 /** 92 * @deprecated use the constructor that provides a {@link Lifecycle} instead 93 */ 94 @Deprecated ConnectivityListener(Context context, Listener listener)95 public ConnectivityListener(Context context, Listener listener) { 96 this(context, listener, null); 97 } 98 ConnectivityListener(Context context, Listener listener, Lifecycle lifecycle)99 public ConnectivityListener(Context context, Listener listener, Lifecycle lifecycle) { 100 mContext = context; 101 mConnectivityManager = (ConnectivityManager) mContext.getSystemService( 102 Context.CONNECTIVITY_SERVICE); 103 mWifiManager = mContext.getSystemService(WifiManager.class); 104 mEthernetManager = mContext.getSystemService(EthernetManager.class); 105 mListener = listener; 106 if (mWifiManager != null) { 107 if (lifecycle != null) { 108 lifecycle.addObserver(this); 109 mWifiTracker = new WifiTracker(context, this, lifecycle, true, true); 110 } else { 111 mWifiTracker = new WifiTracker(context, this, true, true); 112 } 113 } 114 updateConnectivityStatus(); 115 } 116 117 /** 118 * Starts {@link ConnectivityListener}. 119 * This should be called only from main thread. 120 * @deprecated not needed when a {@link Lifecycle} is provided 121 */ 122 @UiThread 123 @Deprecated start()124 public void start() { 125 if (!mStarted && mWifiTracker != null) { 126 mWifiTracker.onStart(); 127 } 128 onStart(); 129 } 130 131 @Override onStart()132 public void onStart() { 133 if (!mStarted) { 134 mStarted = true; 135 updateConnectivityStatus(); 136 IntentFilter networkIntentFilter = new IntentFilter(); 137 networkIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); 138 networkIntentFilter.addAction(WifiManager.RSSI_CHANGED_ACTION); 139 networkIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); 140 networkIntentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); 141 142 mContext.registerReceiver(mNetworkReceiver, networkIntentFilter); 143 final TelephonyManager telephonyManager = mContext 144 .getSystemService(TelephonyManager.class); 145 if (telephonyManager != null) { 146 telephonyManager.listen(mPhoneStateListener, 147 PhoneStateListener.LISTEN_SIGNAL_STRENGTHS); 148 } 149 } 150 } 151 152 /** 153 * Stops {@link ConnectivityListener}. 154 * This should be called only from main thread. 155 * @deprecated not needed when a {@link Lifecycle} is provided 156 */ 157 @UiThread 158 @Deprecated stop()159 public void stop() { 160 if (mStarted && mWifiTracker != null) { 161 mWifiTracker.onStop(); 162 } 163 onStop(); 164 } 165 166 @Override onStop()167 public void onStop() { 168 if (mStarted) { 169 mStarted = false; 170 mContext.unregisterReceiver(mNetworkReceiver); 171 mWifiListener = null; 172 final TelephonyManager telephonyManager = mContext 173 .getSystemService(TelephonyManager.class); 174 if (telephonyManager != null) { 175 telephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE); 176 } 177 } 178 } 179 180 /** 181 * Causes the background thread to quit. 182 * @deprecated not needed when a {@link Lifecycle} is provided 183 */ 184 @Deprecated destroy()185 public void destroy() { 186 if (mWifiTracker != null) { 187 mWifiTracker.onDestroy(); 188 } 189 } 190 setWifiListener(WifiNetworkListener wifiListener)191 public void setWifiListener(WifiNetworkListener wifiListener) { 192 mWifiListener = wifiListener; 193 } 194 getWifiIpAddress()195 public String getWifiIpAddress() { 196 if (isWifiConnected()) { 197 Network network = mWifiManager.getCurrentNetwork(); 198 return formatIpAddresses(network); 199 } else { 200 return ""; 201 } 202 } 203 204 /** 205 * Return the MAC address of the currently connected Wifi AP. 206 */ 207 @SuppressLint("HardwareIds") getWifiMacAddress(AccessPoint ap)208 public String getWifiMacAddress(AccessPoint ap) { 209 if (isWifiConnected() && mWifiManager.getConnectionInfo() != null) { 210 return mWifiManager.getConnectionInfo().getMacAddress(); 211 } 212 if (ap != null) { 213 WifiConfiguration wifiConfig = ap.getConfig(); 214 if (wifiConfig != null 215 && wifiConfig.macRandomizationSetting 216 == WifiConfiguration.RANDOMIZATION_PERSISTENT) { 217 return wifiConfig.getRandomizedMacAddress().toString(); 218 } 219 } 220 221 // return device MAC address 222 final String[] macAddresses = mWifiManager.getFactoryMacAddresses(); 223 if (macAddresses != null && macAddresses.length > 0) { 224 return macAddresses[0]; 225 } 226 227 Log.e(TAG, "Unable to get MAC address"); 228 return ""; 229 } 230 231 /** Return whether the connected Wifi supports MAC address randomization. */ isMacAddressRandomizationSupported()232 public boolean isMacAddressRandomizationSupported() { 233 return mWifiManager.isConnectedMacRandomizationSupported(); 234 } 235 236 /** Return whether the MAC address of the currently connected Wifi AP is randomized. */ getWifiMacRandomizationSetting(AccessPoint ap)237 public int getWifiMacRandomizationSetting(AccessPoint ap) { 238 if (ap == null || ap.getConfig() == null) { 239 return WifiConfiguration.RANDOMIZATION_NONE; 240 } 241 return ap.getConfig().macRandomizationSetting; 242 } 243 244 /** Apply the setting of whether to use MAC address randimization. */ applyMacRandomizationSetting(AccessPoint ap, boolean enable)245 public void applyMacRandomizationSetting(AccessPoint ap, boolean enable) { 246 if (ap != null && ap.getConfig() != null) { 247 ap.getConfig().macRandomizationSetting = enable 248 ? WifiConfiguration.RANDOMIZATION_PERSISTENT 249 : WifiConfiguration.RANDOMIZATION_NONE; 250 mWifiManager.updateNetwork(ap.getConfig()); 251 // To activate changing, we need to reconnect network. WiFi will auto connect to 252 // current network after disconnect(). Only needed when this is connected network. 253 final WifiInfo wifiInfo = mWifiManager.getConnectionInfo(); 254 if (wifiInfo != null && wifiInfo.getNetworkId() == ap.getConfig().networkId) { 255 mWifiManager.disconnect(); 256 } 257 } 258 } 259 isEthernetConnected()260 public boolean isEthernetConnected() { 261 return mNetworkType == ConnectivityManager.TYPE_ETHERNET; 262 } 263 isWifiConnected()264 public boolean isWifiConnected() { 265 if (mNetworkType == ConnectivityManager.TYPE_WIFI) { 266 return true; 267 } else { 268 if (mWifiManager != null) { 269 WifiInfo connectionInfo = mWifiManager.getConnectionInfo(); 270 return connectionInfo.getNetworkId() != -1; 271 } 272 } 273 return false; 274 } 275 isCellConnected()276 public boolean isCellConnected() { 277 return mNetworkType == ConnectivityManager.TYPE_MOBILE; 278 } 279 280 /** 281 * Return whether Ethernet port is available. 282 */ isEthernetAvailable()283 public boolean isEthernetAvailable() { 284 return mConnectivityManager.isNetworkSupported(ConnectivityManager.TYPE_ETHERNET) 285 && mEthernetManager.getAvailableInterfaces().length > 0; 286 } 287 getFirstEthernet()288 private Network getFirstEthernet() { 289 final Network[] networks = mConnectivityManager.getAllNetworks(); 290 for (final Network network : networks) { 291 NetworkInfo networkInfo = mConnectivityManager.getNetworkInfo(network); 292 if (networkInfo != null && networkInfo.getType() == ConnectivityManager.TYPE_ETHERNET) { 293 return network; 294 } 295 } 296 return null; 297 } 298 formatIpAddresses(Network network)299 private String formatIpAddresses(Network network) { 300 final LinkProperties linkProperties = mConnectivityManager.getLinkProperties(network); 301 if (linkProperties == null) { 302 return null; 303 } 304 final StringBuilder sb = new StringBuilder(); 305 boolean gotAddress = false; 306 for (LinkAddress linkAddress : linkProperties.getLinkAddresses()) { 307 if (gotAddress) { 308 sb.append("\n"); 309 } 310 sb.append(linkAddress.getAddress().getHostAddress()); 311 gotAddress = true; 312 } 313 if (gotAddress) { 314 return sb.toString(); 315 } else { 316 return null; 317 } 318 } 319 320 /** 321 * Returns the formatted IP addresses of the Ethernet connection or null 322 * if none available. 323 */ getEthernetIpAddress()324 public String getEthernetIpAddress() { 325 final Network network = getFirstEthernet(); 326 if (network == null) { 327 return null; 328 } 329 return formatIpAddresses(network); 330 } 331 getWifiSignalStrength(int maxLevel)332 public int getWifiSignalStrength(int maxLevel) { 333 if (mWifiManager != null) { 334 WifiInfo wifiInfo = mWifiManager.getConnectionInfo(); 335 return WifiManager.calculateSignalLevel(wifiInfo.getRssi(), maxLevel); 336 } 337 return 0; 338 } 339 getCellSignalStrength()340 public int getCellSignalStrength() { 341 if (isCellConnected() && mCellSignalStrength != null) { 342 return mCellSignalStrength.getLevel(); 343 } else { 344 return 0; 345 } 346 } 347 348 /** 349 * Return a list of wifi networks. Ensure that if a wifi network is connected that it appears 350 * as the first item on the list. 351 */ getAvailableNetworks()352 public List<AccessPoint> getAvailableNetworks() { 353 return mWifiTracker == null ? new ArrayList<>() : mWifiTracker.getAccessPoints(); 354 } 355 isWifiEnabledOrEnabling()356 public boolean isWifiEnabledOrEnabling() { 357 return mWifiManager != null 358 && (mWifiManager.getWifiState() == WifiManager.WIFI_STATE_ENABLED 359 || mWifiManager.getWifiState() == WifiManager.WIFI_STATE_ENABLING); 360 } 361 setWifiEnabled(boolean enable)362 public void setWifiEnabled(boolean enable) { 363 if (mWifiManager != null) { 364 mWifiManager.setWifiEnabled(enable); 365 } 366 } 367 updateConnectivityStatus()368 private void updateConnectivityStatus() { 369 NetworkInfo networkInfo = mConnectivityManager.getActiveNetworkInfo(); 370 if (networkInfo == null) { 371 mNetworkType = ConnectivityManager.TYPE_NONE; 372 } else { 373 switch (networkInfo.getType()) { 374 case ConnectivityManager.TYPE_WIFI: { 375 376 if (mWifiManager == null) { 377 break; 378 } 379 // Determine if this is 380 // an open or secure wifi connection. 381 mNetworkType = ConnectivityManager.TYPE_WIFI; 382 383 String ssid = getSsid(); 384 if (!TextUtils.equals(mWifiSsid, ssid)) { 385 mWifiSsid = ssid; 386 } 387 388 WifiInfo wifiInfo = mWifiManager.getConnectionInfo(); 389 // Calculate the signal strength. 390 int signalStrength; 391 if (wifiInfo != null) { 392 // Calculate the signal strength between 0 and 3. 393 signalStrength = WifiManager.calculateSignalLevel(wifiInfo.getRssi(), 4); 394 } else { 395 signalStrength = 0; 396 } 397 if (mWifiSignalStrength != signalStrength) { 398 mWifiSignalStrength = signalStrength; 399 } 400 break; 401 } 402 403 case ConnectivityManager.TYPE_ETHERNET: 404 mNetworkType = ConnectivityManager.TYPE_ETHERNET; 405 break; 406 407 case ConnectivityManager.TYPE_MOBILE: 408 mNetworkType = ConnectivityManager.TYPE_MOBILE; 409 break; 410 411 default: 412 mNetworkType = ConnectivityManager.TYPE_NONE; 413 break; 414 } 415 } 416 } 417 418 @Override onWifiStateChanged(int state)419 public void onWifiStateChanged(int state) { 420 updateConnectivityStatus(); 421 if (mListener != null) { 422 mListener.onConnectivityChange(); 423 } 424 } 425 426 @Override onConnectedChanged()427 public void onConnectedChanged() { 428 updateConnectivityStatus(); 429 if (mListener != null) { 430 mListener.onConnectivityChange(); 431 } 432 } 433 434 @Override onAccessPointsChanged()435 public void onAccessPointsChanged() { 436 if (mWifiListener != null) { 437 mWifiListener.onWifiListChanged(); 438 } 439 } 440 441 public interface Listener { onConnectivityChange()442 void onConnectivityChange(); 443 } 444 445 public interface WifiNetworkListener { onWifiListChanged()446 void onWifiListChanged(); 447 } 448 449 /** 450 * Get the SSID of current connected network. 451 * @return SSID 452 */ getSsid()453 public String getSsid() { 454 if (mWifiManager == null) { 455 return null; 456 } 457 WifiInfo wifiInfo = mWifiManager.getConnectionInfo(); 458 // Find the SSID of network. 459 String ssid = null; 460 if (wifiInfo != null) { 461 ssid = wifiInfo.getSSID(); 462 if (ssid != null) { 463 ssid = WifiInfo.sanitizeSsid(ssid); 464 } 465 } 466 return ssid; 467 } 468 } 469