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