blob: 7ee795f924b3a03d440dafc0aa69050c56e885d9 [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;
Chris Wrenf6e9228b2016-01-26 18:04:35 -050027
Chris Wren457a21c2015-05-06 17:50:34 -040028import com.android.internal.logging.MetricsLogger;
Chris Wrenf6e9228b2016-01-26 18:04:35 -050029import com.android.internal.logging.MetricsProto.MetricsEvent;
Jason Monkd52356a2015-01-28 10:40:41 -050030import com.android.settingslib.wifi.AccessPoint;
John Spurlockaf8d6c42014-05-07 17:49:08 -040031import com.android.systemui.R;
John Spurlock486b78e2014-07-07 08:37:56 -040032import com.android.systemui.qs.QSDetailItems;
33import com.android.systemui.qs.QSDetailItems.Item;
Jason Monkdc35dcb2015-12-04 16:36:15 -050034import com.android.systemui.qs.QSIconView;
John Spurlockaf8d6c42014-05-07 17:49:08 -040035import com.android.systemui.qs.QSTile;
John Spurlockaf8d6c42014-05-07 17:49:08 -040036import com.android.systemui.qs.SignalTileView;
37import com.android.systemui.statusbar.policy.NetworkController;
Jason Monkd2263cd2014-11-10 14:22:56 -050038import com.android.systemui.statusbar.policy.NetworkController.AccessPointController;
Jason Monk07b75fe2015-05-14 16:47:03 -040039import com.android.systemui.statusbar.policy.NetworkController.IconState;
Jason Monk07b75fe2015-05-14 16:47:03 -040040import com.android.systemui.statusbar.policy.SignalCallbackAdapter;
41
42import java.util.List;
John Spurlockaf8d6c42014-05-07 17:49:08 -040043
44/** Quick settings tile: Wifi **/
45public class WifiTile extends QSTile<QSTile.SignalState> {
46 private static final Intent WIFI_SETTINGS = new Intent(Settings.ACTION_WIFI_SETTINGS);
47
48 private final NetworkController mController;
Jason Monkd2263cd2014-11-10 14:22:56 -050049 private final AccessPointController mWifiController;
John Spurlock7f8f22a2014-07-02 18:54:17 -040050 private final WifiDetailAdapter mDetailAdapter;
Selim Cinek4fda7b22014-08-18 22:07:25 +020051 private final QSTile.SignalState mStateBeforeClick = newTileState();
John Spurlockaf8d6c42014-05-07 17:49:08 -040052
Jason Monkf1179612015-09-23 11:11:00 -040053 protected final WifiSignalCallback mSignalCallback = new WifiSignalCallback();
Jason Monk878c0932015-07-21 10:18:01 -040054
Jason Monkdc35dcb2015-12-04 16:36:15 -050055 public WifiTile(Host host) {
John Spurlockaf8d6c42014-05-07 17:49:08 -040056 super(host);
57 mController = host.getNetworkController();
Jason Monkd2263cd2014-11-10 14:22:56 -050058 mWifiController = mController.getAccessPointController();
John Spurlock7f8f22a2014-07-02 18:54:17 -040059 mDetailAdapter = new WifiDetailAdapter();
John Spurlockccb6b9a2014-05-17 15:54:40 -040060 }
61
62 @Override
Jason Monk62b63a02016-02-02 15:15:31 -050063 public SignalState newTileState() {
John Spurlockaf8d6c42014-05-07 17:49:08 -040064 return new SignalState();
65 }
66
67 @Override
John Spurlockccb6b9a2014-05-17 15:54:40 -040068 public void setListening(boolean listening) {
69 if (listening) {
Jason Monk07b75fe2015-05-14 16:47:03 -040070 mController.addSignalCallback(mSignalCallback);
John Spurlockccb6b9a2014-05-17 15:54:40 -040071 } else {
Jason Monk07b75fe2015-05-14 16:47:03 -040072 mController.removeSignalCallback(mSignalCallback);
Jason Monk0d6a1c42015-04-20 16:38:51 -040073 }
74 }
75
76 @Override
77 public void setDetailListening(boolean listening) {
78 if (listening) {
79 mWifiController.addAccessPointCallback(mDetailAdapter);
80 } else {
Jason Monkd2263cd2014-11-10 14:22:56 -050081 mWifiController.removeAccessPointCallback(mDetailAdapter);
John Spurlockccb6b9a2014-05-17 15:54:40 -040082 }
John Spurlockaf8d6c42014-05-07 17:49:08 -040083 }
84
85 @Override
John Spurlock7f8f22a2014-07-02 18:54:17 -040086 public DetailAdapter getDetailAdapter() {
87 return mDetailAdapter;
88 }
89
90 @Override
Jason Monkdc35dcb2015-12-04 16:36:15 -050091 public QSIconView createTileView(Context context) {
John Spurlockaf8d6c42014-05-07 17:49:08 -040092 return new SignalTileView(context);
93 }
94
95 @Override
Jason Monk76c67aa2016-02-19 14:49:42 -050096 public Intent getLongClickIntent() {
97 return WIFI_SETTINGS;
98 }
99
100 @Override
Jason Monkdc35dcb2015-12-04 16:36:15 -0500101 protected void handleSecondaryClick() {
102 // Secondary clicks are header clicks, just toggle.
Selim Cinek4fda7b22014-08-18 22:07:25 +0200103 mState.copyTo(mStateBeforeClick);
Chris Wren9e7283f2015-05-08 17:23:47 -0400104 MetricsLogger.action(mContext, getMetricsCategory(), !mState.enabled);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400105 mController.setWifiEnabled(!mState.enabled);
106 }
107
108 @Override
Jason Monkdc35dcb2015-12-04 16:36:15 -0500109 protected void handleClick() {
Jason Monkd2263cd2014-11-10 14:22:56 -0500110 if (!mWifiController.canConfigWifi()) {
Jason Monkee43cdf2015-06-19 14:20:46 -0400111 mHost.startActivityDismissingKeyguard(new Intent(Settings.ACTION_WIFI_SETTINGS));
Jason Monk5d325072014-10-27 11:38:47 -0400112 return;
113 }
114 if (!mState.enabled) {
115 mController.setWifiEnabled(true);
116 mState.enabled = true;
117 }
118 showDetail(true);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400119 }
120
121 @Override
122 protected void handleUpdateState(SignalState state, Object arg) {
John Spurlockccb6b9a2014-05-17 15:54:40 -0400123 if (DEBUG) Log.d(TAG, "handleUpdateState arg=" + arg);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400124 CallbackInfo cb = (CallbackInfo) arg;
Jason Monk878c0932015-07-21 10:18:01 -0400125 if (cb == null) {
126 cb = mSignalCallback.mInfo;
127 }
John Spurlockaf8d6c42014-05-07 17:49:08 -0400128
129 boolean wifiConnected = cb.enabled && (cb.wifiSignalIconId > 0) && (cb.enabledDesc != null);
130 boolean wifiNotConnected = (cb.wifiSignalIconId > 0) && (cb.enabledDesc == null);
John Spurlock7f8f22a2014-07-02 18:54:17 -0400131 boolean enabledChanging = state.enabled != cb.enabled;
132 if (enabledChanging) {
John Spurlock486b78e2014-07-07 08:37:56 -0400133 mDetailAdapter.setItemsVisible(cb.enabled);
John Spurlock7f8f22a2014-07-02 18:54:17 -0400134 fireToggleStateChanged(cb.enabled);
135 }
John Spurlock3d09bbd2014-05-22 12:20:16 -0400136 state.enabled = cb.enabled;
John Spurlockaf8d6c42014-05-07 17:49:08 -0400137 state.connected = wifiConnected;
138 state.activityIn = cb.enabled && cb.activityIn;
139 state.activityOut = cb.enabled && cb.activityOut;
John Spurlock899f4392014-06-11 10:59:11 -0400140 state.filter = true;
John Spurlockaf8d6c42014-05-07 17:49:08 -0400141 final String signalContentDescription;
142 final Resources r = mContext.getResources();
John Spurlockc1d48a52014-08-01 12:12:32 -0400143 if (!state.enabled) {
John Spurlock2d695812014-10-30 13:25:21 -0400144 state.icon = ResourceIcon.get(R.drawable.ic_qs_wifi_disabled);
John Spurlockc1d48a52014-08-01 12:12:32 -0400145 state.label = r.getString(R.string.quick_settings_wifi_label);
146 signalContentDescription = r.getString(R.string.accessibility_wifi_off);
147 } else if (wifiConnected) {
John Spurlock2d695812014-10-30 13:25:21 -0400148 state.icon = ResourceIcon.get(cb.wifiSignalIconId);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400149 state.label = removeDoubleQuotes(cb.enabledDesc);
150 signalContentDescription = cb.wifiSignalContentDescription;
151 } else if (wifiNotConnected) {
Jason Monk7d0e5982015-07-08 12:09:52 -0400152 state.icon = ResourceIcon.get(R.drawable.ic_qs_wifi_full_0);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400153 state.label = r.getString(R.string.quick_settings_wifi_label);
154 signalContentDescription = r.getString(R.string.accessibility_no_wifi);
155 } else {
John Spurlock2d695812014-10-30 13:25:21 -0400156 state.icon = ResourceIcon.get(R.drawable.ic_qs_wifi_no_network);
John Spurlock012d4a22014-06-04 00:40:18 -0400157 state.label = r.getString(R.string.quick_settings_wifi_label);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400158 signalContentDescription = r.getString(R.string.accessibility_wifi_off);
159 }
160 state.contentDescription = mContext.getString(
161 R.string.accessibility_quick_settings_wifi,
Selim Cineke5557a92014-08-15 19:59:23 +0200162 signalContentDescription);
Jason Monkbbadff82015-11-06 15:47:26 -0500163 CharSequence wifiName = state.label;
Selim Cineke5557a92014-08-15 19:59:23 +0200164 if (state.connected) {
165 wifiName = r.getString(R.string.accessibility_wifi_name, state.label);
166 }
167 state.dualLabelContentDescription = wifiName;
John Spurlockaf8d6c42014-05-07 17:49:08 -0400168 }
169
Selim Cinek4fda7b22014-08-18 22:07:25 +0200170 @Override
Chris Wren457a21c2015-05-06 17:50:34 -0400171 public int getMetricsCategory() {
Chris Wrenf6e9228b2016-01-26 18:04:35 -0500172 return MetricsEvent.QS_WIFI;
Chris Wren457a21c2015-05-06 17:50:34 -0400173 }
174
175 @Override
Selim Cinek4fda7b22014-08-18 22:07:25 +0200176 protected boolean shouldAnnouncementBeDelayed() {
177 return mStateBeforeClick.enabled == mState.enabled;
178 }
179
180 @Override
181 protected String composeChangeAnnouncement() {
182 if (mState.enabled) {
183 return mContext.getString(R.string.accessibility_quick_settings_wifi_changed_on);
184 } else {
185 return mContext.getString(R.string.accessibility_quick_settings_wifi_changed_off);
186 }
187 }
188
Jason Monkc3f42c12016-02-05 12:33:13 -0500189 @Override
190 public boolean isAvailable() {
191 return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI);
192 }
193
John Spurlockaf8d6c42014-05-07 17:49:08 -0400194 private static String removeDoubleQuotes(String string) {
195 if (string == null) return null;
196 final int length = string.length();
197 if ((length > 1) && (string.charAt(0) == '"') && (string.charAt(length - 1) == '"')) {
198 return string.substring(1, length - 1);
199 }
200 return string;
201 }
202
Jason Monkf1179612015-09-23 11:11:00 -0400203 protected static final class CallbackInfo {
John Spurlockaf8d6c42014-05-07 17:49:08 -0400204 boolean enabled;
John Spurlockd5cd2fd2014-07-27 11:36:33 -0400205 boolean connected;
John Spurlockaf8d6c42014-05-07 17:49:08 -0400206 int wifiSignalIconId;
207 String enabledDesc;
208 boolean activityIn;
209 boolean activityOut;
210 String wifiSignalContentDescription;
John Spurlockccb6b9a2014-05-17 15:54:40 -0400211
212 @Override
213 public String toString() {
214 return new StringBuilder("CallbackInfo[")
215 .append("enabled=").append(enabled)
John Spurlockd5cd2fd2014-07-27 11:36:33 -0400216 .append(",connected=").append(connected)
John Spurlockccb6b9a2014-05-17 15:54:40 -0400217 .append(",wifiSignalIconId=").append(wifiSignalIconId)
218 .append(",enabledDesc=").append(enabledDesc)
219 .append(",activityIn=").append(activityIn)
220 .append(",activityOut=").append(activityOut)
221 .append(",wifiSignalContentDescription=").append(wifiSignalContentDescription)
222 .append(']').toString();
223 }
John Spurlockaf8d6c42014-05-07 17:49:08 -0400224 }
225
Jason Monkf1179612015-09-23 11:11:00 -0400226 protected final class WifiSignalCallback extends SignalCallbackAdapter {
Jason Monk878c0932015-07-21 10:18:01 -0400227 final CallbackInfo mInfo = new CallbackInfo();
228
John Spurlockaf8d6c42014-05-07 17:49:08 -0400229 @Override
Jason Monk07b75fe2015-05-14 16:47:03 -0400230 public void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon,
231 boolean activityIn, boolean activityOut, String description) {
John Spurlockccb6b9a2014-05-17 15:54:40 -0400232 if (DEBUG) Log.d(TAG, "onWifiSignalChanged enabled=" + enabled);
Jason Monk878c0932015-07-21 10:18:01 -0400233 mInfo.enabled = enabled;
234 mInfo.connected = qsIcon.visible;
235 mInfo.wifiSignalIconId = qsIcon.icon;
236 mInfo.enabledDesc = description;
237 mInfo.activityIn = activityIn;
238 mInfo.activityOut = activityOut;
239 mInfo.wifiSignalContentDescription = qsIcon.contentDescription;
240 refreshState(mInfo);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400241 }
John Spurlockaf8d6c42014-05-07 17:49:08 -0400242 };
John Spurlock7f8f22a2014-07-02 18:54:17 -0400243
244 private final class WifiDetailAdapter implements DetailAdapter,
Jason Monkd2263cd2014-11-10 14:22:56 -0500245 NetworkController.AccessPointController.AccessPointCallback, QSDetailItems.Callback {
John Spurlock7f8f22a2014-07-02 18:54:17 -0400246
John Spurlock486b78e2014-07-07 08:37:56 -0400247 private QSDetailItems mItems;
John Spurlock7f8f22a2014-07-02 18:54:17 -0400248 private AccessPoint[] mAccessPoints;
249
250 @Override
Jason Monkc06fbb12016-01-08 14:12:18 -0500251 public CharSequence getTitle() {
252 return mContext.getString(R.string.quick_settings_wifi_label);
John Spurlock7f8f22a2014-07-02 18:54:17 -0400253 }
254
255 public Intent getSettingsIntent() {
256 return WIFI_SETTINGS;
257 }
258
259 @Override
260 public Boolean getToggleState() {
261 return mState.enabled;
262 }
263
264 @Override
265 public void setToggleState(boolean state) {
266 if (DEBUG) Log.d(TAG, "setToggleState " + state);
Chris Wrenf6e9228b2016-01-26 18:04:35 -0500267 MetricsLogger.action(mContext, MetricsEvent.QS_WIFI_TOGGLE, state);
John Spurlock7f8f22a2014-07-02 18:54:17 -0400268 mController.setWifiEnabled(state);
269 showDetail(false);
270 }
271
272 @Override
Chris Wren457a21c2015-05-06 17:50:34 -0400273 public int getMetricsCategory() {
Chris Wrenf6e9228b2016-01-26 18:04:35 -0500274 return MetricsEvent.QS_WIFI_DETAILS;
Chris Wren457a21c2015-05-06 17:50:34 -0400275 }
276
277 @Override
John Spurlock7f8f22a2014-07-02 18:54:17 -0400278 public View createDetailView(Context context, View convertView, ViewGroup parent) {
John Spurlock486b78e2014-07-07 08:37:56 -0400279 if (DEBUG) Log.d(TAG, "createDetailView convertView=" + (convertView != null));
280 mAccessPoints = null;
Jason Monkd2263cd2014-11-10 14:22:56 -0500281 mWifiController.scanForAccessPoints();
John Spurlock486b78e2014-07-07 08:37:56 -0400282 fireScanStateChanged(true);
283 mItems = QSDetailItems.convertOrInflate(context, convertView, parent);
284 mItems.setTagSuffix("Wifi");
285 mItems.setCallback(this);
286 mItems.setEmptyState(R.drawable.ic_qs_wifi_detail_empty,
287 R.string.quick_settings_wifi_detail_empty_text);
John Spurlock7f8f22a2014-07-02 18:54:17 -0400288 updateItems();
John Spurlock486b78e2014-07-07 08:37:56 -0400289 setItemsVisible(mState.enabled);
John Spurlock7f8f22a2014-07-02 18:54:17 -0400290 return mItems;
291 }
292
293 @Override
Jason Monkd52356a2015-01-28 10:40:41 -0500294 public void onAccessPointsChanged(final List<AccessPoint> accessPoints) {
295 mAccessPoints = accessPoints.toArray(new AccessPoint[accessPoints.size()]);
John Spurlock486b78e2014-07-07 08:37:56 -0400296 updateItems();
Jason Monkd52356a2015-01-28 10:40:41 -0500297 if (accessPoints != null && accessPoints.size() > 0) {
John Spurlock486b78e2014-07-07 08:37:56 -0400298 fireScanStateChanged(false);
299 }
John Spurlock7f8f22a2014-07-02 18:54:17 -0400300 }
301
John Spurlock486b78e2014-07-07 08:37:56 -0400302 @Override
Jason Monk17f3c3f2015-01-14 10:13:22 -0500303 public void onSettingsActivityTriggered(Intent settingsIntent) {
Jason Monkee43cdf2015-06-19 14:20:46 -0400304 mHost.startActivityDismissingKeyguard(settingsIntent);
Jason Monk17f3c3f2015-01-14 10:13:22 -0500305 }
306
307 @Override
John Spurlock486b78e2014-07-07 08:37:56 -0400308 public void onDetailItemClick(Item item) {
309 if (item == null || item.tag == null) return;
310 final AccessPoint ap = (AccessPoint) item.tag;
Jason Monkd52356a2015-01-28 10:40:41 -0500311 if (!ap.isActive()) {
Jason Monkd2263cd2014-11-10 14:22:56 -0500312 if (mWifiController.connect(ap)) {
Jason Monk5d325072014-10-27 11:38:47 -0400313 mHost.collapsePanels();
314 }
John Spurlock486b78e2014-07-07 08:37:56 -0400315 }
316 showDetail(false);
317 }
318
319 @Override
320 public void onDetailItemDisconnect(Item item) {
321 // noop
322 }
323
324 public void setItemsVisible(boolean visible) {
325 if (mItems == null) return;
326 mItems.setItemsVisible(visible);
John Spurlock7f8f22a2014-07-02 18:54:17 -0400327 }
328
329 private void updateItems() {
330 if (mItems == null) return;
John Spurlock486b78e2014-07-07 08:37:56 -0400331 Item[] items = null;
332 if (mAccessPoints != null) {
333 items = new Item[mAccessPoints.length];
334 for (int i = 0; i < mAccessPoints.length; i++) {
335 final AccessPoint ap = mAccessPoints[i];
336 final Item item = new Item();
337 item.tag = ap;
Jason Monkd52356a2015-01-28 10:40:41 -0500338 item.icon = mWifiController.getIcon(ap);
339 item.line1 = ap.getSsid();
Jason Monk283c8b72015-05-26 12:54:12 -0400340 item.line2 = ap.isActive() ? ap.getSummary() : null;
Jason Monkd52356a2015-01-28 10:40:41 -0500341 item.overlay = ap.getSecurity() != AccessPoint.SECURITY_NONE
Jason Monkb27ec6d32014-12-01 17:50:16 -0500342 ? mContext.getDrawable(R.drawable.qs_ic_wifi_lock)
343 : null;
John Spurlock486b78e2014-07-07 08:37:56 -0400344 items[i] = item;
345 }
John Spurlock7f8f22a2014-07-02 18:54:17 -0400346 }
John Spurlock486b78e2014-07-07 08:37:56 -0400347 mItems.setItems(items);
John Spurlock7f8f22a2014-07-02 18:54:17 -0400348 }
349 };
John Spurlockaf8d6c42014-05-07 17:49:08 -0400350}