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