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