blob: be2a34a26807e1f907620604a9b8e324805b071b [file] [log] [blame]
John Spurlockaf8d6c42014-05-07 17:49:08 -04001/*
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
17package com.android.systemui.qs.tiles;
18
19import android.content.Context;
20import android.content.Intent;
Jason Monkba2318e2015-12-08 09:04:23 -050021import android.content.pm.PackageManager;
John Spurlockaf8d6c42014-05-07 17:49:08 -040022import android.content.res.Resources;
23import android.provider.Settings;
John Spurlockccb6b9a2014-05-17 15:54:40 -040024import android.util.Log;
John Spurlock7f8f22a2014-07-02 18:54:17 -040025import android.view.View;
John Spurlock7f8f22a2014-07-02 18:54:17 -040026import android.view.ViewGroup;
Julia Reynolds20aef8a2016-05-04 16:44:08 -040027import android.widget.Button;
28import android.widget.Switch;
Chris Wrenf6e9228b2016-01-26 18:04:35 -050029
Chris Wren457a21c2015-05-06 17:50:34 -040030import com.android.internal.logging.MetricsLogger;
Tamas Berghammercbd3f0c2016-06-22 15:21:38 +010031import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
Jason Monkd52356a2015-01-28 10:40:41 -050032import com.android.settingslib.wifi.AccessPoint;
John Spurlockaf8d6c42014-05-07 17:49:08 -040033import com.android.systemui.R;
John Spurlock486b78e2014-07-07 08:37:56 -040034import com.android.systemui.qs.QSDetailItems;
35import com.android.systemui.qs.QSDetailItems.Item;
Jason Monkdc35dcb2015-12-04 16:36:15 -050036import com.android.systemui.qs.QSIconView;
John Spurlockaf8d6c42014-05-07 17:49:08 -040037import com.android.systemui.qs.QSTile;
John Spurlockaf8d6c42014-05-07 17:49:08 -040038import com.android.systemui.qs.SignalTileView;
39import com.android.systemui.statusbar.policy.NetworkController;
Jason Monkd2263cd2014-11-10 14:22:56 -050040import com.android.systemui.statusbar.policy.NetworkController.AccessPointController;
Jason Monk07b75fe2015-05-14 16:47:03 -040041import com.android.systemui.statusbar.policy.NetworkController.IconState;
Jason Monk07b75fe2015-05-14 16:47:03 -040042import com.android.systemui.statusbar.policy.SignalCallbackAdapter;
43
44import java.util.List;
John Spurlockaf8d6c42014-05-07 17:49:08 -040045
46/** Quick settings tile: Wifi **/
47public class WifiTile extends QSTile<QSTile.SignalState> {
48 private static final Intent WIFI_SETTINGS = new Intent(Settings.ACTION_WIFI_SETTINGS);
49
50 private final NetworkController mController;
Jason Monkd2263cd2014-11-10 14:22:56 -050051 private final AccessPointController mWifiController;
John Spurlock7f8f22a2014-07-02 18:54:17 -040052 private final WifiDetailAdapter mDetailAdapter;
Selim Cinek4fda7b22014-08-18 22:07:25 +020053 private final QSTile.SignalState mStateBeforeClick = newTileState();
John Spurlockaf8d6c42014-05-07 17:49:08 -040054
Jason Monkf1179612015-09-23 11:11:00 -040055 protected final WifiSignalCallback mSignalCallback = new WifiSignalCallback();
Jason Monk878c0932015-07-21 10:18:01 -040056
Jason Monkdc35dcb2015-12-04 16:36:15 -050057 public WifiTile(Host host) {
John Spurlockaf8d6c42014-05-07 17:49:08 -040058 super(host);
59 mController = host.getNetworkController();
Jason Monkd2263cd2014-11-10 14:22:56 -050060 mWifiController = mController.getAccessPointController();
John Spurlock7f8f22a2014-07-02 18:54:17 -040061 mDetailAdapter = new WifiDetailAdapter();
John Spurlockccb6b9a2014-05-17 15:54:40 -040062 }
63
64 @Override
Jason Monk62b63a02016-02-02 15:15:31 -050065 public SignalState newTileState() {
John Spurlockaf8d6c42014-05-07 17:49:08 -040066 return new SignalState();
67 }
68
69 @Override
John Spurlockccb6b9a2014-05-17 15:54:40 -040070 public void setListening(boolean listening) {
71 if (listening) {
Jason Monk07b75fe2015-05-14 16:47:03 -040072 mController.addSignalCallback(mSignalCallback);
John Spurlockccb6b9a2014-05-17 15:54:40 -040073 } else {
Jason Monk07b75fe2015-05-14 16:47:03 -040074 mController.removeSignalCallback(mSignalCallback);
Jason Monk0d6a1c42015-04-20 16:38:51 -040075 }
76 }
77
78 @Override
79 public void setDetailListening(boolean listening) {
80 if (listening) {
81 mWifiController.addAccessPointCallback(mDetailAdapter);
82 } else {
Jason Monkd2263cd2014-11-10 14:22:56 -050083 mWifiController.removeAccessPointCallback(mDetailAdapter);
John Spurlockccb6b9a2014-05-17 15:54:40 -040084 }
John Spurlockaf8d6c42014-05-07 17:49:08 -040085 }
86
87 @Override
John Spurlock7f8f22a2014-07-02 18:54:17 -040088 public DetailAdapter getDetailAdapter() {
89 return mDetailAdapter;
90 }
91
92 @Override
Jason Monkdc35dcb2015-12-04 16:36:15 -050093 public QSIconView createTileView(Context context) {
John Spurlockaf8d6c42014-05-07 17:49:08 -040094 return new SignalTileView(context);
95 }
96
97 @Override
Jason Monk76c67aa2016-02-19 14:49:42 -050098 public Intent getLongClickIntent() {
99 return WIFI_SETTINGS;
100 }
101
102 @Override
Jason Monkdc35dcb2015-12-04 16:36:15 -0500103 protected void handleSecondaryClick() {
104 // Secondary clicks are header clicks, just toggle.
Selim Cinek4fda7b22014-08-18 22:07:25 +0200105 mState.copyTo(mStateBeforeClick);
Julia Reynolds20aef8a2016-05-04 16:44:08 -0400106 MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
107 mController.setWifiEnabled(!mState.value);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400108 }
109
110 @Override
Jason Monkdc35dcb2015-12-04 16:36:15 -0500111 protected void handleClick() {
Jason Monkd2263cd2014-11-10 14:22:56 -0500112 if (!mWifiController.canConfigWifi()) {
Jason Monkee43cdf2015-06-19 14:20:46 -0400113 mHost.startActivityDismissingKeyguard(new Intent(Settings.ACTION_WIFI_SETTINGS));
Jason Monk5d325072014-10-27 11:38:47 -0400114 return;
115 }
Jason Monk48e093e2016-07-15 10:37:07 -0400116 showDetail(true);
Julia Reynolds20aef8a2016-05-04 16:44:08 -0400117 if (!mState.value) {
Jason Monk5d325072014-10-27 11:38:47 -0400118 mController.setWifiEnabled(true);
Julia Reynolds20aef8a2016-05-04 16:44:08 -0400119 mState.value = true;
Jason Monk5d325072014-10-27 11:38:47 -0400120 }
John Spurlockaf8d6c42014-05-07 17:49:08 -0400121 }
122
123 @Override
Jason Monk39c98e62016-03-16 09:18:35 -0400124 public CharSequence getTileLabel() {
125 return mContext.getString(R.string.quick_settings_wifi_label);
126 }
127
128 @Override
John Spurlockaf8d6c42014-05-07 17:49:08 -0400129 protected void handleUpdateState(SignalState state, Object arg) {
John Spurlockccb6b9a2014-05-17 15:54:40 -0400130 if (DEBUG) Log.d(TAG, "handleUpdateState arg=" + arg);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400131 CallbackInfo cb = (CallbackInfo) arg;
Jason Monk878c0932015-07-21 10:18:01 -0400132 if (cb == null) {
133 cb = mSignalCallback.mInfo;
134 }
John Spurlockaf8d6c42014-05-07 17:49:08 -0400135
136 boolean wifiConnected = cb.enabled && (cb.wifiSignalIconId > 0) && (cb.enabledDesc != null);
137 boolean wifiNotConnected = (cb.wifiSignalIconId > 0) && (cb.enabledDesc == null);
Julia Reynolds20aef8a2016-05-04 16:44:08 -0400138 boolean enabledChanging = state.value != cb.enabled;
John Spurlock7f8f22a2014-07-02 18:54:17 -0400139 if (enabledChanging) {
John Spurlock486b78e2014-07-07 08:37:56 -0400140 mDetailAdapter.setItemsVisible(cb.enabled);
John Spurlock7f8f22a2014-07-02 18:54:17 -0400141 fireToggleStateChanged(cb.enabled);
142 }
Julia Reynolds20aef8a2016-05-04 16:44:08 -0400143 state.value = cb.enabled;
John Spurlockaf8d6c42014-05-07 17:49:08 -0400144 state.connected = wifiConnected;
145 state.activityIn = cb.enabled && cb.activityIn;
146 state.activityOut = cb.enabled && cb.activityOut;
John Spurlock899f4392014-06-11 10:59:11 -0400147 state.filter = true;
Julia Reynolds20aef8a2016-05-04 16:44:08 -0400148 final StringBuffer minimalContentDescription = new StringBuffer();
149 final StringBuffer expandedContentDescription = new StringBuffer();
John Spurlockaf8d6c42014-05-07 17:49:08 -0400150 final Resources r = mContext.getResources();
Julia Reynolds20aef8a2016-05-04 16:44:08 -0400151 if (!state.value) {
John Spurlock2d695812014-10-30 13:25:21 -0400152 state.icon = ResourceIcon.get(R.drawable.ic_qs_wifi_disabled);
John Spurlockc1d48a52014-08-01 12:12:32 -0400153 state.label = r.getString(R.string.quick_settings_wifi_label);
John Spurlockc1d48a52014-08-01 12:12:32 -0400154 } else if (wifiConnected) {
John Spurlock2d695812014-10-30 13:25:21 -0400155 state.icon = ResourceIcon.get(cb.wifiSignalIconId);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400156 state.label = removeDoubleQuotes(cb.enabledDesc);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400157 } else if (wifiNotConnected) {
Jason Monkbe83cc02016-03-31 13:38:59 -0400158 state.icon = ResourceIcon.get(R.drawable.ic_qs_wifi_disconnected);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400159 state.label = r.getString(R.string.quick_settings_wifi_label);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400160 } else {
John Spurlock2d695812014-10-30 13:25:21 -0400161 state.icon = ResourceIcon.get(R.drawable.ic_qs_wifi_no_network);
John Spurlock012d4a22014-06-04 00:40:18 -0400162 state.label = r.getString(R.string.quick_settings_wifi_label);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400163 }
Julia Reynolds20aef8a2016-05-04 16:44:08 -0400164 minimalContentDescription.append(
165 mContext.getString(R.string.quick_settings_wifi_label)).append(",");
166 if (state.value) {
167 expandedContentDescription.append(
168 r.getString(R.string.quick_settings_wifi_on_label)).append(",");
169 if (wifiConnected) {
170 minimalContentDescription.append(cb.wifiSignalContentDescription).append(",");
171 minimalContentDescription.append(removeDoubleQuotes(cb.enabledDesc));
172 expandedContentDescription.append(cb.wifiSignalContentDescription).append(",");
173 expandedContentDescription.append(removeDoubleQuotes(cb.enabledDesc));
174 }
175 } else {
176 expandedContentDescription.append(
177 r.getString(R.string.quick_settings_wifi_off_label));
178 }
179 state.minimalContentDescription = minimalContentDescription;
180 expandedContentDescription.append(",").append(
181 r.getString(R.string.accessibility_quick_settings_open_settings, getTileLabel()));
182 state.contentDescription = expandedContentDescription;
Jason Monkbbadff82015-11-06 15:47:26 -0500183 CharSequence wifiName = state.label;
Selim Cineke5557a92014-08-15 19:59:23 +0200184 if (state.connected) {
185 wifiName = r.getString(R.string.accessibility_wifi_name, state.label);
186 }
187 state.dualLabelContentDescription = wifiName;
Julia Reynolds20aef8a2016-05-04 16:44:08 -0400188 state.expandedAccessibilityClassName = Button.class.getName();
189 state.minimalAccessibilityClassName = Switch.class.getName();
John Spurlockaf8d6c42014-05-07 17:49:08 -0400190 }
191
Selim Cinek4fda7b22014-08-18 22:07:25 +0200192 @Override
Chris Wren457a21c2015-05-06 17:50:34 -0400193 public int getMetricsCategory() {
Chris Wrenf6e9228b2016-01-26 18:04:35 -0500194 return MetricsEvent.QS_WIFI;
Chris Wren457a21c2015-05-06 17:50:34 -0400195 }
196
197 @Override
Selim Cinek4fda7b22014-08-18 22:07:25 +0200198 protected boolean shouldAnnouncementBeDelayed() {
Julia Reynolds20aef8a2016-05-04 16:44:08 -0400199 return mStateBeforeClick.value == mState.value;
Selim Cinek4fda7b22014-08-18 22:07:25 +0200200 }
201
202 @Override
203 protected String composeChangeAnnouncement() {
Julia Reynolds20aef8a2016-05-04 16:44:08 -0400204 if (mState.value) {
Selim Cinek4fda7b22014-08-18 22:07:25 +0200205 return mContext.getString(R.string.accessibility_quick_settings_wifi_changed_on);
206 } else {
207 return mContext.getString(R.string.accessibility_quick_settings_wifi_changed_off);
208 }
209 }
210
Jason Monkc3f42c12016-02-05 12:33:13 -0500211 @Override
212 public boolean isAvailable() {
213 return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI);
214 }
215
John Spurlockaf8d6c42014-05-07 17:49:08 -0400216 private static String removeDoubleQuotes(String string) {
217 if (string == null) return null;
218 final int length = string.length();
219 if ((length > 1) && (string.charAt(0) == '"') && (string.charAt(length - 1) == '"')) {
220 return string.substring(1, length - 1);
221 }
222 return string;
223 }
224
Jason Monkf1179612015-09-23 11:11:00 -0400225 protected static final class CallbackInfo {
John Spurlockaf8d6c42014-05-07 17:49:08 -0400226 boolean enabled;
John Spurlockd5cd2fd2014-07-27 11:36:33 -0400227 boolean connected;
John Spurlockaf8d6c42014-05-07 17:49:08 -0400228 int wifiSignalIconId;
229 String enabledDesc;
230 boolean activityIn;
231 boolean activityOut;
232 String wifiSignalContentDescription;
John Spurlockccb6b9a2014-05-17 15:54:40 -0400233
234 @Override
235 public String toString() {
236 return new StringBuilder("CallbackInfo[")
237 .append("enabled=").append(enabled)
John Spurlockd5cd2fd2014-07-27 11:36:33 -0400238 .append(",connected=").append(connected)
John Spurlockccb6b9a2014-05-17 15:54:40 -0400239 .append(",wifiSignalIconId=").append(wifiSignalIconId)
240 .append(",enabledDesc=").append(enabledDesc)
241 .append(",activityIn=").append(activityIn)
242 .append(",activityOut=").append(activityOut)
243 .append(",wifiSignalContentDescription=").append(wifiSignalContentDescription)
244 .append(']').toString();
245 }
John Spurlockaf8d6c42014-05-07 17:49:08 -0400246 }
247
Jason Monkf1179612015-09-23 11:11:00 -0400248 protected final class WifiSignalCallback extends SignalCallbackAdapter {
Jason Monk878c0932015-07-21 10:18:01 -0400249 final CallbackInfo mInfo = new CallbackInfo();
250
John Spurlockaf8d6c42014-05-07 17:49:08 -0400251 @Override
Jason Monk07b75fe2015-05-14 16:47:03 -0400252 public void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon,
253 boolean activityIn, boolean activityOut, String description) {
John Spurlockccb6b9a2014-05-17 15:54:40 -0400254 if (DEBUG) Log.d(TAG, "onWifiSignalChanged enabled=" + enabled);
Jason Monk878c0932015-07-21 10:18:01 -0400255 mInfo.enabled = enabled;
256 mInfo.connected = qsIcon.visible;
257 mInfo.wifiSignalIconId = qsIcon.icon;
258 mInfo.enabledDesc = description;
259 mInfo.activityIn = activityIn;
260 mInfo.activityOut = activityOut;
261 mInfo.wifiSignalContentDescription = qsIcon.contentDescription;
262 refreshState(mInfo);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400263 }
John Spurlockaf8d6c42014-05-07 17:49:08 -0400264 };
John Spurlock7f8f22a2014-07-02 18:54:17 -0400265
266 private final class WifiDetailAdapter implements DetailAdapter,
Jason Monkd2263cd2014-11-10 14:22:56 -0500267 NetworkController.AccessPointController.AccessPointCallback, QSDetailItems.Callback {
John Spurlock7f8f22a2014-07-02 18:54:17 -0400268
John Spurlock486b78e2014-07-07 08:37:56 -0400269 private QSDetailItems mItems;
John Spurlock7f8f22a2014-07-02 18:54:17 -0400270 private AccessPoint[] mAccessPoints;
271
272 @Override
Jason Monkc06fbb12016-01-08 14:12:18 -0500273 public CharSequence getTitle() {
274 return mContext.getString(R.string.quick_settings_wifi_label);
John Spurlock7f8f22a2014-07-02 18:54:17 -0400275 }
276
277 public Intent getSettingsIntent() {
278 return WIFI_SETTINGS;
279 }
280
281 @Override
282 public Boolean getToggleState() {
Julia Reynolds20aef8a2016-05-04 16:44:08 -0400283 return mState.value;
John Spurlock7f8f22a2014-07-02 18:54:17 -0400284 }
285
286 @Override
287 public void setToggleState(boolean state) {
288 if (DEBUG) Log.d(TAG, "setToggleState " + state);
Chris Wrenf6e9228b2016-01-26 18:04:35 -0500289 MetricsLogger.action(mContext, MetricsEvent.QS_WIFI_TOGGLE, state);
John Spurlock7f8f22a2014-07-02 18:54:17 -0400290 mController.setWifiEnabled(state);
291 showDetail(false);
292 }
293
294 @Override
Chris Wren457a21c2015-05-06 17:50:34 -0400295 public int getMetricsCategory() {
Chris Wrenf6e9228b2016-01-26 18:04:35 -0500296 return MetricsEvent.QS_WIFI_DETAILS;
Chris Wren457a21c2015-05-06 17:50:34 -0400297 }
298
299 @Override
John Spurlock7f8f22a2014-07-02 18:54:17 -0400300 public View createDetailView(Context context, View convertView, ViewGroup parent) {
John Spurlock486b78e2014-07-07 08:37:56 -0400301 if (DEBUG) Log.d(TAG, "createDetailView convertView=" + (convertView != null));
302 mAccessPoints = null;
Jason Monkd2263cd2014-11-10 14:22:56 -0500303 mWifiController.scanForAccessPoints();
John Spurlock486b78e2014-07-07 08:37:56 -0400304 fireScanStateChanged(true);
305 mItems = QSDetailItems.convertOrInflate(context, convertView, parent);
306 mItems.setTagSuffix("Wifi");
307 mItems.setCallback(this);
308 mItems.setEmptyState(R.drawable.ic_qs_wifi_detail_empty,
309 R.string.quick_settings_wifi_detail_empty_text);
John Spurlock7f8f22a2014-07-02 18:54:17 -0400310 updateItems();
Julia Reynolds20aef8a2016-05-04 16:44:08 -0400311 setItemsVisible(mState.value);
John Spurlock7f8f22a2014-07-02 18:54:17 -0400312 return mItems;
313 }
314
315 @Override
Jason Monkd52356a2015-01-28 10:40:41 -0500316 public void onAccessPointsChanged(final List<AccessPoint> accessPoints) {
317 mAccessPoints = accessPoints.toArray(new AccessPoint[accessPoints.size()]);
John Spurlock486b78e2014-07-07 08:37:56 -0400318 updateItems();
Jason Monkd52356a2015-01-28 10:40:41 -0500319 if (accessPoints != null && accessPoints.size() > 0) {
John Spurlock486b78e2014-07-07 08:37:56 -0400320 fireScanStateChanged(false);
321 }
John Spurlock7f8f22a2014-07-02 18:54:17 -0400322 }
323
John Spurlock486b78e2014-07-07 08:37:56 -0400324 @Override
Jason Monk17f3c3f2015-01-14 10:13:22 -0500325 public void onSettingsActivityTriggered(Intent settingsIntent) {
Jason Monkee43cdf2015-06-19 14:20:46 -0400326 mHost.startActivityDismissingKeyguard(settingsIntent);
Jason Monk17f3c3f2015-01-14 10:13:22 -0500327 }
328
329 @Override
John Spurlock486b78e2014-07-07 08:37:56 -0400330 public void onDetailItemClick(Item item) {
331 if (item == null || item.tag == null) return;
332 final AccessPoint ap = (AccessPoint) item.tag;
Jason Monkd52356a2015-01-28 10:40:41 -0500333 if (!ap.isActive()) {
Jason Monkd2263cd2014-11-10 14:22:56 -0500334 if (mWifiController.connect(ap)) {
Jason Monk5d325072014-10-27 11:38:47 -0400335 mHost.collapsePanels();
336 }
John Spurlock486b78e2014-07-07 08:37:56 -0400337 }
338 showDetail(false);
339 }
340
341 @Override
342 public void onDetailItemDisconnect(Item item) {
343 // noop
344 }
345
346 public void setItemsVisible(boolean visible) {
347 if (mItems == null) return;
348 mItems.setItemsVisible(visible);
John Spurlock7f8f22a2014-07-02 18:54:17 -0400349 }
350
351 private void updateItems() {
352 if (mItems == null) return;
John Spurlock486b78e2014-07-07 08:37:56 -0400353 Item[] items = null;
354 if (mAccessPoints != null) {
355 items = new Item[mAccessPoints.length];
356 for (int i = 0; i < mAccessPoints.length; i++) {
357 final AccessPoint ap = mAccessPoints[i];
358 final Item item = new Item();
359 item.tag = ap;
Jason Monkd52356a2015-01-28 10:40:41 -0500360 item.icon = mWifiController.getIcon(ap);
361 item.line1 = ap.getSsid();
Jason Monk283c8b72015-05-26 12:54:12 -0400362 item.line2 = ap.isActive() ? ap.getSummary() : null;
Jason Monkd52356a2015-01-28 10:40:41 -0500363 item.overlay = ap.getSecurity() != AccessPoint.SECURITY_NONE
Jason Monkb27ec6d32014-12-01 17:50:16 -0500364 ? mContext.getDrawable(R.drawable.qs_ic_wifi_lock)
365 : null;
John Spurlock486b78e2014-07-07 08:37:56 -0400366 items[i] = item;
367 }
John Spurlock7f8f22a2014-07-02 18:54:17 -0400368 }
John Spurlock486b78e2014-07-07 08:37:56 -0400369 mItems.setItems(items);
John Spurlock7f8f22a2014-07-02 18:54:17 -0400370 }
Fan Zhang3bfda442016-07-15 10:39:03 -0700371 }
John Spurlockaf8d6c42014-05-07 17:49:08 -0400372}