1/* 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; 21import android.content.res.Resources; 22import android.provider.Settings; 23import android.util.Log; 24import android.view.View; 25import android.view.ViewGroup; 26 27import com.android.internal.logging.MetricsLogger; 28import com.android.settingslib.wifi.AccessPoint; 29import com.android.systemui.R; 30import com.android.systemui.qs.QSDetailItems; 31import com.android.systemui.qs.QSDetailItems.Item; 32import com.android.systemui.qs.QSTile; 33import com.android.systemui.qs.QSTileView; 34import com.android.systemui.qs.SignalTileView; 35import com.android.systemui.statusbar.policy.NetworkController; 36import com.android.systemui.statusbar.policy.NetworkController.AccessPointController; 37import com.android.systemui.statusbar.policy.NetworkController.IconState; 38import com.android.systemui.statusbar.policy.SignalCallbackAdapter; 39 40import java.util.List; 41 42/** Quick settings tile: Wifi **/ 43public class WifiTile extends QSTile<QSTile.SignalState> { 44 private static final Intent WIFI_SETTINGS = new Intent(Settings.ACTION_WIFI_SETTINGS); 45 46 private final NetworkController mController; 47 private final AccessPointController mWifiController; 48 private final WifiDetailAdapter mDetailAdapter; 49 private final QSTile.SignalState mStateBeforeClick = newTileState(); 50 51 private final WifiSignalCallback mSignalCallback = new WifiSignalCallback(); 52 53 public WifiTile(Host host) { 54 super(host); 55 mController = host.getNetworkController(); 56 mWifiController = mController.getAccessPointController(); 57 mDetailAdapter = new WifiDetailAdapter(); 58 } 59 60 @Override 61 public boolean supportsDualTargets() { 62 return true; 63 } 64 65 @Override 66 protected SignalState newTileState() { 67 return new SignalState(); 68 } 69 70 @Override 71 public void setListening(boolean listening) { 72 if (listening) { 73 mController.addSignalCallback(mSignalCallback); 74 } else { 75 mController.removeSignalCallback(mSignalCallback); 76 } 77 } 78 79 @Override 80 public void setDetailListening(boolean listening) { 81 if (listening) { 82 mWifiController.addAccessPointCallback(mDetailAdapter); 83 } else { 84 mWifiController.removeAccessPointCallback(mDetailAdapter); 85 } 86 } 87 88 @Override 89 public DetailAdapter getDetailAdapter() { 90 return mDetailAdapter; 91 } 92 93 @Override 94 public QSTileView createTileView(Context context) { 95 return new SignalTileView(context); 96 } 97 98 @Override 99 protected void handleClick() { 100 mState.copyTo(mStateBeforeClick); 101 MetricsLogger.action(mContext, getMetricsCategory(), !mState.enabled); 102 mController.setWifiEnabled(!mState.enabled); 103 } 104 105 @Override 106 protected void handleSecondaryClick() { 107 if (!mWifiController.canConfigWifi()) { 108 mHost.startActivityDismissingKeyguard(new Intent(Settings.ACTION_WIFI_SETTINGS)); 109 return; 110 } 111 if (!mState.enabled) { 112 mController.setWifiEnabled(true); 113 mState.enabled = true; 114 } 115 showDetail(true); 116 } 117 118 @Override 119 protected void handleUpdateState(SignalState state, Object arg) { 120 state.visible = true; 121 if (DEBUG) Log.d(TAG, "handleUpdateState arg=" + arg); 122 CallbackInfo cb = (CallbackInfo) arg; 123 if (cb == null) { 124 cb = mSignalCallback.mInfo; 125 } 126 127 boolean wifiConnected = cb.enabled && (cb.wifiSignalIconId > 0) && (cb.enabledDesc != null); 128 boolean wifiNotConnected = (cb.wifiSignalIconId > 0) && (cb.enabledDesc == null); 129 boolean enabledChanging = state.enabled != cb.enabled; 130 if (enabledChanging) { 131 mDetailAdapter.setItemsVisible(cb.enabled); 132 fireToggleStateChanged(cb.enabled); 133 } 134 state.enabled = cb.enabled; 135 state.connected = wifiConnected; 136 state.activityIn = cb.enabled && cb.activityIn; 137 state.activityOut = cb.enabled && cb.activityOut; 138 state.filter = true; 139 final String signalContentDescription; 140 final Resources r = mContext.getResources(); 141 if (!state.enabled) { 142 state.icon = ResourceIcon.get(R.drawable.ic_qs_wifi_disabled); 143 state.label = r.getString(R.string.quick_settings_wifi_label); 144 signalContentDescription = r.getString(R.string.accessibility_wifi_off); 145 } else if (wifiConnected) { 146 state.icon = ResourceIcon.get(cb.wifiSignalIconId); 147 state.label = removeDoubleQuotes(cb.enabledDesc); 148 signalContentDescription = cb.wifiSignalContentDescription; 149 } else if (wifiNotConnected) { 150 state.icon = ResourceIcon.get(R.drawable.ic_qs_wifi_full_0); 151 state.label = r.getString(R.string.quick_settings_wifi_label); 152 signalContentDescription = r.getString(R.string.accessibility_no_wifi); 153 } else { 154 state.icon = ResourceIcon.get(R.drawable.ic_qs_wifi_no_network); 155 state.label = r.getString(R.string.quick_settings_wifi_label); 156 signalContentDescription = r.getString(R.string.accessibility_wifi_off); 157 } 158 state.contentDescription = mContext.getString( 159 R.string.accessibility_quick_settings_wifi, 160 signalContentDescription); 161 String wifiName = state.label; 162 if (state.connected) { 163 wifiName = r.getString(R.string.accessibility_wifi_name, state.label); 164 } 165 state.dualLabelContentDescription = wifiName; 166 } 167 168 @Override 169 public int getMetricsCategory() { 170 return MetricsLogger.QS_WIFI; 171 } 172 173 @Override 174 protected boolean shouldAnnouncementBeDelayed() { 175 return mStateBeforeClick.enabled == mState.enabled; 176 } 177 178 @Override 179 protected String composeChangeAnnouncement() { 180 if (mState.enabled) { 181 return mContext.getString(R.string.accessibility_quick_settings_wifi_changed_on); 182 } else { 183 return mContext.getString(R.string.accessibility_quick_settings_wifi_changed_off); 184 } 185 } 186 187 private static String removeDoubleQuotes(String string) { 188 if (string == null) return null; 189 final int length = string.length(); 190 if ((length > 1) && (string.charAt(0) == '"') && (string.charAt(length - 1) == '"')) { 191 return string.substring(1, length - 1); 192 } 193 return string; 194 } 195 196 private static final class CallbackInfo { 197 boolean enabled; 198 boolean connected; 199 int wifiSignalIconId; 200 String enabledDesc; 201 boolean activityIn; 202 boolean activityOut; 203 String wifiSignalContentDescription; 204 205 @Override 206 public String toString() { 207 return new StringBuilder("CallbackInfo[") 208 .append("enabled=").append(enabled) 209 .append(",connected=").append(connected) 210 .append(",wifiSignalIconId=").append(wifiSignalIconId) 211 .append(",enabledDesc=").append(enabledDesc) 212 .append(",activityIn=").append(activityIn) 213 .append(",activityOut=").append(activityOut) 214 .append(",wifiSignalContentDescription=").append(wifiSignalContentDescription) 215 .append(']').toString(); 216 } 217 } 218 219 private final class WifiSignalCallback extends SignalCallbackAdapter { 220 final CallbackInfo mInfo = new CallbackInfo(); 221 222 @Override 223 public void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon, 224 boolean activityIn, boolean activityOut, String description) { 225 if (DEBUG) Log.d(TAG, "onWifiSignalChanged enabled=" + enabled); 226 mInfo.enabled = enabled; 227 mInfo.connected = qsIcon.visible; 228 mInfo.wifiSignalIconId = qsIcon.icon; 229 mInfo.enabledDesc = description; 230 mInfo.activityIn = activityIn; 231 mInfo.activityOut = activityOut; 232 mInfo.wifiSignalContentDescription = qsIcon.contentDescription; 233 refreshState(mInfo); 234 } 235 }; 236 237 private final class WifiDetailAdapter implements DetailAdapter, 238 NetworkController.AccessPointController.AccessPointCallback, QSDetailItems.Callback { 239 240 private QSDetailItems mItems; 241 private AccessPoint[] mAccessPoints; 242 243 @Override 244 public int getTitle() { 245 return R.string.quick_settings_wifi_label; 246 } 247 248 public Intent getSettingsIntent() { 249 return WIFI_SETTINGS; 250 } 251 252 @Override 253 public Boolean getToggleState() { 254 return mState.enabled; 255 } 256 257 @Override 258 public void setToggleState(boolean state) { 259 if (DEBUG) Log.d(TAG, "setToggleState " + state); 260 MetricsLogger.action(mContext, MetricsLogger.QS_WIFI_TOGGLE, state); 261 mController.setWifiEnabled(state); 262 showDetail(false); 263 } 264 265 @Override 266 public int getMetricsCategory() { 267 return MetricsLogger.QS_WIFI_DETAILS; 268 } 269 270 @Override 271 public View createDetailView(Context context, View convertView, ViewGroup parent) { 272 if (DEBUG) Log.d(TAG, "createDetailView convertView=" + (convertView != null)); 273 mAccessPoints = null; 274 mWifiController.scanForAccessPoints(); 275 fireScanStateChanged(true); 276 mItems = QSDetailItems.convertOrInflate(context, convertView, parent); 277 mItems.setTagSuffix("Wifi"); 278 mItems.setCallback(this); 279 mItems.setEmptyState(R.drawable.ic_qs_wifi_detail_empty, 280 R.string.quick_settings_wifi_detail_empty_text); 281 updateItems(); 282 setItemsVisible(mState.enabled); 283 return mItems; 284 } 285 286 @Override 287 public void onAccessPointsChanged(final List<AccessPoint> accessPoints) { 288 mAccessPoints = accessPoints.toArray(new AccessPoint[accessPoints.size()]); 289 updateItems(); 290 if (accessPoints != null && accessPoints.size() > 0) { 291 fireScanStateChanged(false); 292 } 293 } 294 295 @Override 296 public void onSettingsActivityTriggered(Intent settingsIntent) { 297 mHost.startActivityDismissingKeyguard(settingsIntent); 298 } 299 300 @Override 301 public void onDetailItemClick(Item item) { 302 if (item == null || item.tag == null) return; 303 final AccessPoint ap = (AccessPoint) item.tag; 304 if (!ap.isActive()) { 305 if (mWifiController.connect(ap)) { 306 mHost.collapsePanels(); 307 } 308 } 309 showDetail(false); 310 } 311 312 @Override 313 public void onDetailItemDisconnect(Item item) { 314 // noop 315 } 316 317 public void setItemsVisible(boolean visible) { 318 if (mItems == null) return; 319 mItems.setItemsVisible(visible); 320 } 321 322 private void updateItems() { 323 if (mItems == null) return; 324 Item[] items = null; 325 if (mAccessPoints != null) { 326 items = new Item[mAccessPoints.length]; 327 for (int i = 0; i < mAccessPoints.length; i++) { 328 final AccessPoint ap = mAccessPoints[i]; 329 final Item item = new Item(); 330 item.tag = ap; 331 item.icon = mWifiController.getIcon(ap); 332 item.line1 = ap.getSsid(); 333 item.line2 = ap.isActive() ? ap.getSummary() : null; 334 item.overlay = ap.getSecurity() != AccessPoint.SECURITY_NONE 335 ? mContext.getDrawable(R.drawable.qs_ic_wifi_lock) 336 : null; 337 items[i] = item; 338 } 339 } 340 mItems.setItems(items); 341 } 342 }; 343} 344