• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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