• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
5  *
6  *      http://www.apache.org/licenses/LICENSE-2.0
7  *
8  * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
9  */
10 
11 package com.android.settingslib.wifi;
12 
13 import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
14 import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY;
15 import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
16 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
17 
18 import android.content.Context;
19 import android.content.Intent;
20 import android.net.ConnectivityManager;
21 import android.net.ConnectivityManager.NetworkCallback;
22 import android.net.Network;
23 import android.net.NetworkCapabilities;
24 import android.net.NetworkInfo;
25 import android.net.NetworkKey;
26 import android.net.NetworkRequest;
27 import android.net.NetworkScoreManager;
28 import android.net.ScoredNetwork;
29 import android.net.wifi.WifiConfiguration;
30 import android.net.wifi.WifiInfo;
31 import android.net.wifi.WifiManager;
32 import android.net.wifi.WifiNetworkScoreCache;
33 import android.os.Handler;
34 import android.os.Looper;
35 import android.provider.Settings;
36 
37 import com.android.settingslib.R;
38 
39 import java.util.List;
40 
41 /**
42  * Track status of Wi-Fi for the Sys UI.
43  */
44 public class WifiStatusTracker {
45     private final Context mContext;
46     private final WifiNetworkScoreCache mWifiNetworkScoreCache;
47     private final WifiManager mWifiManager;
48     private final NetworkScoreManager mNetworkScoreManager;
49     private final ConnectivityManager mConnectivityManager;
50     private final Handler mHandler = new Handler(Looper.getMainLooper());
51     private final WifiNetworkScoreCache.CacheListener mCacheListener =
52             new WifiNetworkScoreCache.CacheListener(mHandler) {
53                 @Override
54                 public void networkCacheUpdated(List<ScoredNetwork> updatedNetworks) {
55                     updateStatusLabel();
56                     mCallback.run();
57                 }
58             };
59     private final NetworkRequest mNetworkRequest = new NetworkRequest.Builder()
60             .clearCapabilities()
61             .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
62             .addTransportType(NetworkCapabilities.TRANSPORT_WIFI).build();
63     private final NetworkCallback mNetworkCallback = new NetworkCallback() {
64         // Note: onCapabilitiesChanged is guaranteed to be called "immediately" after onAvailable
65         // and onLinkPropertiesChanged.
66         @Override
67         public void onCapabilitiesChanged(
68                 Network network, NetworkCapabilities networkCapabilities) {
69             updateStatusLabel();
70             mCallback.run();
71         }
72     };
73     private final NetworkCallback mDefaultNetworkCallback = new NetworkCallback() {
74                 @Override
75                 public void onCapabilitiesChanged(Network network, NetworkCapabilities nc) {
76                     // network is now the default network, and its capabilities are nc.
77                     // This method will always be called immediately after the network becomes the
78                     // default, in addition to any time the capabilities change while the network is
79                     // the default.
80                     mDefaultNetwork = network;
81                     mDefaultNetworkCapabilities = nc;
82                     updateStatusLabel();
83                     mCallback.run();
84                 }
85                 @Override
86                 public void onLost(Network network) {
87                     // The system no longer has a default network.
88                     mDefaultNetwork = null;
89                     mDefaultNetworkCapabilities = null;
90                     updateStatusLabel();
91                     mCallback.run();
92                 }
93             };
94     private Network mDefaultNetwork = null;
95     private NetworkCapabilities mDefaultNetworkCapabilities = null;
96     private final Runnable mCallback;
97 
98     private WifiInfo mWifiInfo;
99     public boolean enabled;
100     public boolean isCaptivePortal;
101     public boolean isDefaultNetwork;
102     public int state;
103     public boolean connected;
104     public String ssid;
105     public int rssi;
106     public int level;
107     public String statusLabel;
108 
WifiStatusTracker(Context context, WifiManager wifiManager, NetworkScoreManager networkScoreManager, ConnectivityManager connectivityManager, Runnable callback)109     public WifiStatusTracker(Context context, WifiManager wifiManager,
110             NetworkScoreManager networkScoreManager, ConnectivityManager connectivityManager,
111             Runnable callback) {
112         mContext = context;
113         mWifiManager = wifiManager;
114         mWifiNetworkScoreCache = new WifiNetworkScoreCache(context);
115         mNetworkScoreManager = networkScoreManager;
116         mConnectivityManager = connectivityManager;
117         mCallback = callback;
118     }
119 
setListening(boolean listening)120     public void setListening(boolean listening) {
121         if (listening) {
122             mNetworkScoreManager.registerNetworkScoreCache(NetworkKey.TYPE_WIFI,
123                     mWifiNetworkScoreCache, NetworkScoreManager.SCORE_FILTER_CURRENT_NETWORK);
124             mWifiNetworkScoreCache.registerListener(mCacheListener);
125             mConnectivityManager.registerNetworkCallback(
126                     mNetworkRequest, mNetworkCallback, mHandler);
127             mConnectivityManager.registerDefaultNetworkCallback(mDefaultNetworkCallback, mHandler);
128         } else {
129             mNetworkScoreManager.unregisterNetworkScoreCache(NetworkKey.TYPE_WIFI,
130                     mWifiNetworkScoreCache);
131             mWifiNetworkScoreCache.unregisterListener();
132             mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
133             mConnectivityManager.unregisterNetworkCallback(mDefaultNetworkCallback);
134         }
135     }
136 
137     /**
138      * Fetches initial state as if a WifiManager.NETWORK_STATE_CHANGED_ACTION have been received.
139      * This replaces the dependency on the initial sticky broadcast.
140      */
fetchInitialState()141     public void fetchInitialState() {
142         if (mWifiManager == null) {
143             return;
144         }
145         updateWifiState();
146         final NetworkInfo networkInfo =
147                 mConnectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
148         connected = networkInfo != null && networkInfo.isConnected();
149         mWifiInfo = null;
150         ssid = null;
151         if (connected) {
152             mWifiInfo = mWifiManager.getConnectionInfo();
153             if (mWifiInfo != null) {
154                 if (mWifiInfo.isPasspointAp() || mWifiInfo.isOsuAp()) {
155                     ssid = mWifiInfo.getPasspointProviderFriendlyName();
156                 } else {
157                     ssid = getValidSsid(mWifiInfo);
158                 }
159                 updateRssi(mWifiInfo.getRssi());
160                 maybeRequestNetworkScore();
161             }
162         }
163         updateStatusLabel();
164     }
165 
handleBroadcast(Intent intent)166     public void handleBroadcast(Intent intent) {
167         if (mWifiManager == null) {
168             return;
169         }
170         String action = intent.getAction();
171         if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
172             updateWifiState();
173         } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
174             updateWifiState();
175             final NetworkInfo networkInfo =
176                     intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
177             connected = networkInfo != null && networkInfo.isConnected();
178             mWifiInfo = null;
179             ssid = null;
180             if (connected) {
181                 mWifiInfo = mWifiManager.getConnectionInfo();
182                 if (mWifiInfo != null) {
183                     if (mWifiInfo.isPasspointAp() || mWifiInfo.isOsuAp()) {
184                         ssid = mWifiInfo.getPasspointProviderFriendlyName();
185                     } else {
186                         ssid = getValidSsid(mWifiInfo);
187                     }
188                     updateRssi(mWifiInfo.getRssi());
189                     maybeRequestNetworkScore();
190                 }
191             }
192             updateStatusLabel();
193             mCallback.run();
194         } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
195             // Default to -200 as its below WifiManager.MIN_RSSI.
196             updateRssi(intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200));
197             updateStatusLabel();
198             mCallback.run();
199         }
200     }
201 
updateWifiState()202     private void updateWifiState() {
203         state = mWifiManager.getWifiState();
204         enabled = state == WifiManager.WIFI_STATE_ENABLED;
205     }
206 
updateRssi(int newRssi)207     private void updateRssi(int newRssi) {
208         rssi = newRssi;
209         level = mWifiManager.calculateSignalLevel(rssi);
210     }
211 
maybeRequestNetworkScore()212     private void maybeRequestNetworkScore() {
213         NetworkKey networkKey = NetworkKey.createFromWifiInfo(mWifiInfo);
214         if (mWifiNetworkScoreCache.getScoredNetwork(networkKey) == null) {
215             mNetworkScoreManager.requestScores(new NetworkKey[]{ networkKey });
216         }
217     }
218 
updateStatusLabel()219     private void updateStatusLabel() {
220         NetworkCapabilities networkCapabilities;
221         isDefaultNetwork = false;
222         if (mDefaultNetworkCapabilities != null) {
223             isDefaultNetwork = mDefaultNetworkCapabilities.hasTransport(
224                     NetworkCapabilities.TRANSPORT_WIFI);
225         }
226         if (isDefaultNetwork) {
227             // Wifi is connected and the default network.
228             networkCapabilities = mDefaultNetworkCapabilities;
229         } else {
230             networkCapabilities = mConnectivityManager.getNetworkCapabilities(
231                     mWifiManager.getCurrentNetwork());
232         }
233         isCaptivePortal = false;
234         if (networkCapabilities != null) {
235             if (networkCapabilities.hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL)) {
236                 statusLabel = mContext.getString(R.string.wifi_status_sign_in_required);
237                 isCaptivePortal = true;
238                 return;
239             } else if (networkCapabilities.hasCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY)) {
240                 statusLabel = mContext.getString(R.string.wifi_limited_connection);
241                 return;
242             } else if (!networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)) {
243                 final String mode = Settings.Global.getString(mContext.getContentResolver(),
244                         Settings.Global.PRIVATE_DNS_MODE);
245                 if (networkCapabilities.isPrivateDnsBroken()) {
246                     statusLabel = mContext.getString(R.string.private_dns_broken);
247                 } else {
248                     statusLabel = mContext.getString(R.string.wifi_status_no_internet);
249                 }
250                 return;
251             } else if (!isDefaultNetwork && mDefaultNetworkCapabilities != null
252                     && mDefaultNetworkCapabilities.hasTransport(TRANSPORT_CELLULAR)) {
253                 statusLabel = mContext.getString(R.string.wifi_connected_low_quality);
254                 return;
255             }
256         }
257 
258         ScoredNetwork scoredNetwork =
259                 mWifiNetworkScoreCache.getScoredNetwork(NetworkKey.createFromWifiInfo(mWifiInfo));
260         statusLabel = scoredNetwork == null
261                 ? null : AccessPoint.getSpeedLabel(mContext, scoredNetwork, rssi);
262     }
263 
264     /** Refresh the status label on Locale changed. */
refreshLocale()265     public void refreshLocale() {
266         updateStatusLabel();
267         mCallback.run();
268     }
269 
getValidSsid(WifiInfo info)270     private String getValidSsid(WifiInfo info) {
271         String ssid = info.getSSID();
272         if (ssid != null && !WifiManager.UNKNOWN_SSID.equals(ssid)) {
273             return ssid;
274         }
275         // OK, it's not in the connectionInfo; we have to go hunting for it
276         List<WifiConfiguration> networks = mWifiManager.getConfiguredNetworks();
277         int length = networks.size();
278         for (int i = 0; i < length; i++) {
279             if (networks.get(i).networkId == info.getNetworkId()) {
280                 return networks.get(i).SSID;
281             }
282         }
283         return null;
284     }
285 }
286