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