blob: a97ca5009341791266c963386ea33e2f8f581109 [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;
20import android.net.NetworkCapabilities;
21import android.net.NetworkInfo;
22import android.net.wifi.WifiConfiguration;
23import android.net.wifi.WifiInfo;
24import android.net.wifi.WifiManager;
25import android.os.Handler;
26import android.os.Message;
27import android.os.Messenger;
28import android.util.Log;
29
30import com.android.internal.annotations.VisibleForTesting;
31import com.android.internal.util.AsyncChannel;
32import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback;
33import com.android.systemui.statusbar.policy.NetworkControllerImpl.SignalCluster;
34
35import java.util.List;
36import java.util.Objects;
37
38
39public class WifiSignalController extends
40 SignalController<WifiSignalController.WifiState, SignalController.IconGroup> {
41 private final WifiManager mWifiManager;
42 private final AsyncChannel mWifiChannel;
43 private final boolean mHasMobileData;
44
45 public WifiSignalController(Context context, boolean hasMobileData,
46 List<NetworkSignalChangedCallback> signalCallbacks,
47 List<SignalCluster> signalClusters, NetworkControllerImpl networkController) {
48 super("WifiSignalController", context, NetworkCapabilities.TRANSPORT_WIFI,
49 signalCallbacks, signalClusters, networkController);
50 mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
51 mHasMobileData = hasMobileData;
52 Handler handler = new WifiHandler();
53 mWifiChannel = new AsyncChannel();
54 Messenger wifiMessenger = mWifiManager.getWifiServiceMessenger();
55 if (wifiMessenger != null) {
56 mWifiChannel.connect(context, handler, wifiMessenger);
57 }
58 // WiFi only has one state.
59 mCurrentState.iconGroup = mLastState.iconGroup = new IconGroup(
60 "Wi-Fi Icons",
61 WifiIcons.WIFI_SIGNAL_STRENGTH,
62 WifiIcons.QS_WIFI_SIGNAL_STRENGTH,
63 AccessibilityContentDescriptions.WIFI_CONNECTION_STRENGTH,
64 WifiIcons.WIFI_NO_NETWORK,
65 WifiIcons.QS_WIFI_NO_NETWORK,
66 WifiIcons.WIFI_NO_NETWORK,
67 WifiIcons.QS_WIFI_NO_NETWORK,
68 AccessibilityContentDescriptions.WIFI_NO_CONNECTION
69 );
70 }
71
72 @Override
73 protected WifiState cleanState() {
74 return new WifiState();
75 }
76
77 @Override
78 public void notifyListeners() {
79 // only show wifi in the cluster if connected or if wifi-only
80 boolean wifiVisible = mCurrentState.enabled
81 && (mCurrentState.connected || !mHasMobileData);
82 String wifiDesc = wifiVisible ? mCurrentState.ssid : null;
83 boolean ssidPresent = wifiVisible && mCurrentState.ssid != null;
84 String contentDescription = getStringIfExists(getContentDescription());
85 int length = mSignalsChangedCallbacks.size();
86 for (int i = 0; i < length; i++) {
87 mSignalsChangedCallbacks.get(i).onWifiSignalChanged(mCurrentState.enabled,
88 mCurrentState.connected, getQsCurrentIconId(),
89 ssidPresent && mCurrentState.activityIn,
90 ssidPresent && mCurrentState.activityOut, contentDescription, wifiDesc);
91 }
92
93 int signalClustersLength = mSignalClusters.size();
94 for (int i = 0; i < signalClustersLength; i++) {
95 mSignalClusters.get(i).setWifiIndicators(wifiVisible, getCurrentIconId(),
96 contentDescription);
97 }
98 }
99
100 /**
101 * Extract wifi state directly from broadcasts about changes in wifi state.
102 */
103 public void handleBroadcast(Intent intent) {
104 String action = intent.getAction();
105 if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
106 mCurrentState.enabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
107 WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED;
108 } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
109 final NetworkInfo networkInfo = (NetworkInfo)
110 intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
111 mCurrentState.connected = networkInfo != null && networkInfo.isConnected();
112 // If Connected grab the signal strength and ssid.
113 if (mCurrentState.connected) {
114 // try getting it out of the intent first
115 WifiInfo info = intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO) != null
116 ? (WifiInfo) intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO)
117 : mWifiManager.getConnectionInfo();
118 if (info != null) {
119 mCurrentState.ssid = getSsid(info);
120 } else {
121 mCurrentState.ssid = null;
122 }
123 } else if (!mCurrentState.connected) {
124 mCurrentState.ssid = null;
125 }
126 } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
127 // Default to -200 as its below WifiManager.MIN_RSSI.
128 mCurrentState.rssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200);
129 mCurrentState.level = WifiManager.calculateSignalLevel(
130 mCurrentState.rssi, WifiIcons.WIFI_LEVEL_COUNT);
131 }
132
133 notifyListenersIfNecessary();
134 }
135
136 private String getSsid(WifiInfo info) {
137 String ssid = info.getSSID();
138 if (ssid != null) {
139 return ssid;
140 }
141 // OK, it's not in the connectionInfo; we have to go hunting for it
142 List<WifiConfiguration> networks = mWifiManager.getConfiguredNetworks();
143 int length = networks.size();
144 for (int i = 0; i < length; i++) {
145 if (networks.get(i).networkId == info.getNetworkId()) {
146 return networks.get(i).SSID;
147 }
148 }
149 return null;
150 }
151
152 @VisibleForTesting
153 void setActivity(int wifiActivity) {
154 mCurrentState.activityIn = wifiActivity == WifiManager.DATA_ACTIVITY_INOUT
155 || wifiActivity == WifiManager.DATA_ACTIVITY_IN;
156 mCurrentState.activityOut = wifiActivity == WifiManager.DATA_ACTIVITY_INOUT
157 || wifiActivity == WifiManager.DATA_ACTIVITY_OUT;
158 notifyListenersIfNecessary();
159 }
160
161 /**
162 * Handler to receive the data activity on wifi.
163 */
164 private class WifiHandler extends Handler {
165 @Override
166 public void handleMessage(Message msg) {
167 switch (msg.what) {
168 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
169 if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
170 mWifiChannel.sendMessage(Message.obtain(this,
171 AsyncChannel.CMD_CHANNEL_FULL_CONNECTION));
172 } else {
173 Log.e(mTag, "Failed to connect to wifi");
174 }
175 break;
176 case WifiManager.DATA_ACTIVITY_NOTIFICATION:
177 setActivity(msg.arg1);
178 break;
179 default:
180 // Ignore
181 break;
182 }
183 }
184 }
185
186 static class WifiState extends SignalController.State {
187 String ssid;
188
189 @Override
190 public void copyFrom(State s) {
191 super.copyFrom(s);
192 WifiState state = (WifiState) s;
193 ssid = state.ssid;
194 }
195
196 @Override
197 protected void toString(StringBuilder builder) {
198 super.toString(builder);
199 builder.append(',').append("ssid=").append(ssid);
200 }
201
202 @Override
203 public boolean equals(Object o) {
204 return super.equals(o)
205 && Objects.equals(((WifiState) o).ssid, ssid);
206 }
207 }
208}