blob: 2104cb1421aa65ba7f597f18e72298336404056b [file] [log] [blame]
Jason Monkda68f592015-01-07 10:55:58 -05001/*
2 * Copyright (C) 2015 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 */
16package com.android.systemui.statusbar.policy;
17
18import android.content.Context;
19import android.content.Intent;
Sundeep Ghumand57f3242017-01-13 15:31:48 -080020import android.database.ContentObserver;
Sundeep Ghuman699deaf2017-02-13 15:32:13 -080021import android.net.NetworkBadging;
Jason Monkda68f592015-01-07 10:55:58 -050022import android.net.NetworkCapabilities;
Sundeep Ghumand57f3242017-01-13 15:31:48 -080023import android.net.NetworkKey;
24import android.net.NetworkScoreManager;
25import android.net.ScoredNetwork;
Jason Monkda68f592015-01-07 10:55:58 -050026import android.net.wifi.WifiManager;
Sundeep Ghumand57f3242017-01-13 15:31:48 -080027import android.net.wifi.WifiNetworkScoreCache;
28import android.net.wifi.WifiNetworkScoreCache.CacheListener;
Jason Monkda68f592015-01-07 10:55:58 -050029import android.os.Handler;
Geoffrey Pitsch2c403db2016-08-26 09:09:39 -040030import android.os.Looper;
Jason Monkda68f592015-01-07 10:55:58 -050031import android.os.Message;
32import android.os.Messenger;
Sundeep Ghumand57f3242017-01-13 15:31:48 -080033import android.provider.Settings;
Jason Monkda68f592015-01-07 10:55:58 -050034import android.util.Log;
Winsonc0d70582016-01-29 10:24:39 -080035
Jason Monkda68f592015-01-07 10:55:58 -050036import com.android.internal.annotations.VisibleForTesting;
37import com.android.internal.util.AsyncChannel;
Sundeep Ghumand57f3242017-01-13 15:31:48 -080038import com.android.settingslib.Utils;
Jason Monk4cf95ae2015-11-16 15:59:53 -050039import com.android.settingslib.wifi.WifiStatusTracker;
Jason Monk07b75fe2015-05-14 16:47:03 -040040import com.android.systemui.statusbar.policy.NetworkController.IconState;
Jason Monke06b0652016-03-02 16:35:27 -050041import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
Jason Monkda68f592015-01-07 10:55:58 -050042
Julia Reynolds20aef8a2016-05-04 16:44:08 -040043import com.android.systemui.R;
44
Jason Monkda68f592015-01-07 10:55:58 -050045import java.util.Objects;
Sundeep Ghumand57f3242017-01-13 15:31:48 -080046import java.util.List;
Jason Monkda68f592015-01-07 10:55:58 -050047
48
49public class WifiSignalController extends
50 SignalController<WifiSignalController.WifiState, SignalController.IconGroup> {
Sundeep Ghumand57f3242017-01-13 15:31:48 -080051
Jason Monkda68f592015-01-07 10:55:58 -050052 private final WifiManager mWifiManager;
53 private final AsyncChannel mWifiChannel;
54 private final boolean mHasMobileData;
Sundeep Ghumand57f3242017-01-13 15:31:48 -080055 private final NetworkScoreManager mNetworkScoreManager;
56 private final WifiNetworkScoreCache mScoreCache;
Jason Monk4cf95ae2015-11-16 15:59:53 -050057 private final WifiStatusTracker mWifiTracker;
Jason Monkda68f592015-01-07 10:55:58 -050058
Sundeep Ghumane869d832017-01-25 16:23:43 -080059 private boolean mScoringUiEnabled = false;
Sundeep Ghumand57f3242017-01-13 15:31:48 -080060
Jason Monkda68f592015-01-07 10:55:58 -050061 public WifiSignalController(Context context, boolean hasMobileData,
Sundeep Ghumand57f3242017-01-13 15:31:48 -080062 CallbackHandler callbackHandler, NetworkControllerImpl networkController,
63 NetworkScoreManager networkScoreManager) {
Jason Monkda68f592015-01-07 10:55:58 -050064 super("WifiSignalController", context, NetworkCapabilities.TRANSPORT_WIFI,
Jason Monk07b75fe2015-05-14 16:47:03 -040065 callbackHandler, networkController);
Jason Monkda68f592015-01-07 10:55:58 -050066 mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
Jason Monk4cf95ae2015-11-16 15:59:53 -050067 mWifiTracker = new WifiStatusTracker(mWifiManager);
Jason Monkda68f592015-01-07 10:55:58 -050068 mHasMobileData = hasMobileData;
Geoffrey Pitsch2c403db2016-08-26 09:09:39 -040069 Handler handler = new WifiHandler(Looper.getMainLooper());
Jason Monkda68f592015-01-07 10:55:58 -050070 mWifiChannel = new AsyncChannel();
71 Messenger wifiMessenger = mWifiManager.getWifiServiceMessenger();
72 if (wifiMessenger != null) {
73 mWifiChannel.connect(context, handler, wifiMessenger);
74 }
75 // WiFi only has one state.
76 mCurrentState.iconGroup = mLastState.iconGroup = new IconGroup(
77 "Wi-Fi Icons",
78 WifiIcons.WIFI_SIGNAL_STRENGTH,
79 WifiIcons.QS_WIFI_SIGNAL_STRENGTH,
80 AccessibilityContentDescriptions.WIFI_CONNECTION_STRENGTH,
81 WifiIcons.WIFI_NO_NETWORK,
82 WifiIcons.QS_WIFI_NO_NETWORK,
Jason Monk7e6c83c2017-04-26 14:35:24 -040083 WifiIcons.WIFI_NO_NETWORK,
Jason Monkda68f592015-01-07 10:55:58 -050084 WifiIcons.QS_WIFI_NO_NETWORK,
85 AccessibilityContentDescriptions.WIFI_NO_CONNECTION
86 );
Sundeep Ghumand57f3242017-01-13 15:31:48 -080087
88 mScoreCache = new WifiNetworkScoreCache(context, new CacheListener(handler) {
89 @Override
90 public void networkCacheUpdated(List<ScoredNetwork> networks) {
91 mCurrentState.badgeEnum = getWifiBadgeEnum();
92 notifyListenersIfNecessary();
93 }
94 });
95
96 // Setup scoring
97 mNetworkScoreManager = networkScoreManager;
Sundeep Ghumane869d832017-01-25 16:23:43 -080098 configureScoringGating();
99 registerScoreCache();
100 }
101
102 private void configureScoringGating() {
Sundeep Ghumand57f3242017-01-13 15:31:48 -0800103 ContentObserver observer = new ContentObserver(new Handler(Looper.getMainLooper())) {
104 @Override
105 public void onChange(boolean selfChange) {
Sundeep Ghumane869d832017-01-25 16:23:43 -0800106 mScoringUiEnabled =
Sundeep Ghumand57f3242017-01-13 15:31:48 -0800107 Settings.Global.getInt(
108 mContext.getContentResolver(),
Sundeep Ghumane869d832017-01-25 16:23:43 -0800109 Settings.Global.NETWORK_SCORING_UI_ENABLED, 0) == 1;
Sundeep Ghumand57f3242017-01-13 15:31:48 -0800110 }
111 };
Sundeep Ghumane869d832017-01-25 16:23:43 -0800112 mContext.getContentResolver().registerContentObserver(
113 Settings.Global.getUriFor(Settings.Global.NETWORK_SCORING_UI_ENABLED),
Sundeep Ghumand57f3242017-01-13 15:31:48 -0800114 false /* notifyForDescendants */,
115 observer);
Sundeep Ghumane869d832017-01-25 16:23:43 -0800116
117 observer.onChange(false /* selfChange */); // Set the initial values
Sundeep Ghumand57f3242017-01-13 15:31:48 -0800118 }
119
120 private void registerScoreCache() {
121 Log.d(mTag, "Registered score cache");
122 mNetworkScoreManager.registerNetworkScoreCache(
123 NetworkKey.TYPE_WIFI,
124 mScoreCache,
125 NetworkScoreManager.CACHE_FILTER_CURRENT_NETWORK);
Jason Monkda68f592015-01-07 10:55:58 -0500126 }
127
128 @Override
129 protected WifiState cleanState() {
130 return new WifiState();
131 }
132
133 @Override
Jason Monke06b0652016-03-02 16:35:27 -0500134 public void notifyListeners(SignalCallback callback) {
Jason Monkda68f592015-01-07 10:55:58 -0500135 // only show wifi in the cluster if connected or if wifi-only
Jason Monk7e6c83c2017-04-26 14:35:24 -0400136 boolean wifiVisible = mCurrentState.enabled
137 && (mCurrentState.connected || !mHasMobileData);
Jason Monkda68f592015-01-07 10:55:58 -0500138 String wifiDesc = wifiVisible ? mCurrentState.ssid : null;
139 boolean ssidPresent = wifiVisible && mCurrentState.ssid != null;
140 String contentDescription = getStringIfExists(getContentDescription());
Julia Reynolds20aef8a2016-05-04 16:44:08 -0400141 if (mCurrentState.inetCondition == 0) {
142 contentDescription +=
143 ("," + mContext.getString(R.string.accessibility_quick_settings_no_internet));
144 }
Jason Monkda68f592015-01-07 10:55:58 -0500145
Sundeep Ghumand57f3242017-01-13 15:31:48 -0800146 IconState statusIcon = new IconState(wifiVisible, getCurrentIconId(),
147 Utils.getWifiBadgeResource(mCurrentState.badgeEnum), contentDescription);
148 IconState qsIcon = new IconState(
149 mCurrentState.connected, getQsCurrentIconId(),
150 Utils.getWifiBadgeResource(mCurrentState.badgeEnum), contentDescription);
Jason Monke06b0652016-03-02 16:35:27 -0500151 callback.setWifiIndicators(mCurrentState.enabled, statusIcon, qsIcon,
Jason Monk07b75fe2015-05-14 16:47:03 -0400152 ssidPresent && mCurrentState.activityIn, ssidPresent && mCurrentState.activityOut,
Jason Monk110e5f62017-03-31 13:45:12 -0400153 wifiDesc, mCurrentState.isTransient);
Jason Monkda68f592015-01-07 10:55:58 -0500154 }
155
Sundeep Ghumand57f3242017-01-13 15:31:48 -0800156 @Override
157 public int getCurrentIconId() {
Sundeep Ghuman699deaf2017-02-13 15:32:13 -0800158 if (mCurrentState.badgeEnum != NetworkBadging.BADGING_NONE) {
Sundeep Ghumand57f3242017-01-13 15:31:48 -0800159 return Utils.WIFI_PIE_FOR_BADGING[mCurrentState.level];
160 }
161 return super.getCurrentIconId();
162 }
163
Jason Monkda68f592015-01-07 10:55:58 -0500164 /**
165 * Extract wifi state directly from broadcasts about changes in wifi state.
166 */
167 public void handleBroadcast(Intent intent) {
Sundeep Ghumand57f3242017-01-13 15:31:48 -0800168 // Update the WifiStatusTracker with the new information and update the score cache.
169 NetworkKey previousNetworkKey = mWifiTracker.networkKey;
Jason Monk4cf95ae2015-11-16 15:59:53 -0500170 mWifiTracker.handleBroadcast(intent);
Sundeep Ghumand57f3242017-01-13 15:31:48 -0800171 updateScoreCacheIfNecessary(previousNetworkKey);
172
Jason Monk110e5f62017-03-31 13:45:12 -0400173 mCurrentState.isTransient = mWifiTracker.state == WifiManager.WIFI_STATE_ENABLING
174 || mWifiTracker.state == WifiManager.WIFI_AP_STATE_DISABLING
175 || mWifiTracker.connecting;
Jason Monk4cf95ae2015-11-16 15:59:53 -0500176 mCurrentState.enabled = mWifiTracker.enabled;
177 mCurrentState.connected = mWifiTracker.connected;
178 mCurrentState.ssid = mWifiTracker.ssid;
179 mCurrentState.rssi = mWifiTracker.rssi;
180 mCurrentState.level = mWifiTracker.level;
Sundeep Ghumand57f3242017-01-13 15:31:48 -0800181 mCurrentState.badgeEnum = getWifiBadgeEnum();
Jason Monkda68f592015-01-07 10:55:58 -0500182 notifyListenersIfNecessary();
183 }
184
Sundeep Ghumand57f3242017-01-13 15:31:48 -0800185 /**
186 * Clears old scores out of the cache and requests new scores if the network key has changed.
187 *
188 * <p>New scores are requested asynchronously.
189 */
190 private void updateScoreCacheIfNecessary(NetworkKey previousNetworkKey) {
191 if (mWifiTracker.networkKey == null) {
192 return;
193 }
194 if ((previousNetworkKey == null) || !mWifiTracker.networkKey.equals(previousNetworkKey)) {
195 mScoreCache.clearScores();
196 mNetworkScoreManager.requestScores(new NetworkKey[]{mWifiTracker.networkKey});
197 }
198 }
199
200 /**
201 * Returns the wifi badge enum for the current {@link #mWifiTracker} state.
202 *
203 * <p>{@link #updateScoreCacheIfNecessary} should be called prior to this method.
204 */
205 private int getWifiBadgeEnum() {
Sundeep Ghumane869d832017-01-25 16:23:43 -0800206 if (!mScoringUiEnabled || mWifiTracker.networkKey == null) {
Sundeep Ghuman699deaf2017-02-13 15:32:13 -0800207 return NetworkBadging.BADGING_NONE;
Sundeep Ghumand57f3242017-01-13 15:31:48 -0800208 }
209 ScoredNetwork score = mScoreCache.getScoredNetwork(mWifiTracker.networkKey);
210
211 if (score != null) {
212 return score.calculateBadge(mWifiTracker.rssi);
213 }
Sundeep Ghuman699deaf2017-02-13 15:32:13 -0800214 return NetworkBadging.BADGING_NONE;
Sundeep Ghumand57f3242017-01-13 15:31:48 -0800215 }
216
Jason Monkda68f592015-01-07 10:55:58 -0500217 @VisibleForTesting
218 void setActivity(int wifiActivity) {
219 mCurrentState.activityIn = wifiActivity == WifiManager.DATA_ACTIVITY_INOUT
220 || wifiActivity == WifiManager.DATA_ACTIVITY_IN;
221 mCurrentState.activityOut = wifiActivity == WifiManager.DATA_ACTIVITY_INOUT
222 || wifiActivity == WifiManager.DATA_ACTIVITY_OUT;
223 notifyListenersIfNecessary();
224 }
225
226 /**
227 * Handler to receive the data activity on wifi.
228 */
229 private class WifiHandler extends Handler {
Geoffrey Pitsch2c403db2016-08-26 09:09:39 -0400230 WifiHandler(Looper looper) {
231 super(looper);
232 }
233
Jason Monkda68f592015-01-07 10:55:58 -0500234 @Override
235 public void handleMessage(Message msg) {
236 switch (msg.what) {
237 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
238 if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
239 mWifiChannel.sendMessage(Message.obtain(this,
240 AsyncChannel.CMD_CHANNEL_FULL_CONNECTION));
241 } else {
242 Log.e(mTag, "Failed to connect to wifi");
243 }
244 break;
245 case WifiManager.DATA_ACTIVITY_NOTIFICATION:
246 setActivity(msg.arg1);
247 break;
248 default:
249 // Ignore
250 break;
251 }
252 }
253 }
254
255 static class WifiState extends SignalController.State {
256 String ssid;
Sundeep Ghumand57f3242017-01-13 15:31:48 -0800257 int badgeEnum;
Jason Monk110e5f62017-03-31 13:45:12 -0400258 boolean isTransient;
Jason Monkda68f592015-01-07 10:55:58 -0500259
260 @Override
261 public void copyFrom(State s) {
262 super.copyFrom(s);
263 WifiState state = (WifiState) s;
264 ssid = state.ssid;
Sundeep Ghumand57f3242017-01-13 15:31:48 -0800265 badgeEnum = state.badgeEnum;
Jason Monk110e5f62017-03-31 13:45:12 -0400266 isTransient = state.isTransient;
Jason Monkda68f592015-01-07 10:55:58 -0500267 }
268
269 @Override
270 protected void toString(StringBuilder builder) {
271 super.toString(builder);
272 builder.append(',').append("ssid=").append(ssid);
Jason Monk110e5f62017-03-31 13:45:12 -0400273 builder.append(',').append("badgeEnum=").append(badgeEnum);
274 builder.append(',').append("isTransient=").append(isTransient);
Jason Monkda68f592015-01-07 10:55:58 -0500275 }
276
277 @Override
278 public boolean equals(Object o) {
279 return super.equals(o)
Sundeep Ghumand57f3242017-01-13 15:31:48 -0800280 && Objects.equals(((WifiState) o).ssid, ssid)
Jason Monk110e5f62017-03-31 13:45:12 -0400281 && (((WifiState) o).badgeEnum == badgeEnum)
282 && (((WifiState) o).isTransient == isTransient);
Jason Monkda68f592015-01-07 10:55:58 -0500283 }
284 }
285}