1 /* 2 * Copyright (C) 2020 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.annotation.NonNull; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.content.pm.PackageManager; 23 import android.content.res.Resources; 24 import android.graphics.drawable.Drawable; 25 import android.os.Handler; 26 import android.os.Looper; 27 import android.os.UserHandle; 28 import android.provider.Settings; 29 import android.service.quicksettings.Tile; 30 import android.text.Html; 31 import android.text.TextUtils; 32 import android.util.Log; 33 import android.view.View; 34 import android.widget.Switch; 35 36 import androidx.annotation.Nullable; 37 38 import com.android.internal.annotations.GuardedBy; 39 import com.android.internal.logging.MetricsLogger; 40 import com.android.internal.logging.nano.MetricsProto.MetricsEvent; 41 import com.android.settingslib.graph.SignalDrawable; 42 import com.android.settingslib.mobile.TelephonyIcons; 43 import com.android.settingslib.net.DataUsageController; 44 import com.android.systemui.R; 45 import com.android.systemui.dagger.qualifiers.Background; 46 import com.android.systemui.dagger.qualifiers.Main; 47 import com.android.systemui.plugins.ActivityStarter; 48 import com.android.systemui.plugins.FalsingManager; 49 import com.android.systemui.plugins.qs.QSIconView; 50 import com.android.systemui.plugins.qs.QSTile.SignalState; 51 import com.android.systemui.plugins.statusbar.StatusBarStateController; 52 import com.android.systemui.qs.AlphaControlledSignalTileView; 53 import com.android.systemui.qs.QSHost; 54 import com.android.systemui.qs.QsEventLogger; 55 import com.android.systemui.qs.logging.QSLogger; 56 import com.android.systemui.qs.tileimpl.QSTileImpl; 57 import com.android.systemui.qs.tiles.dialog.InternetDialogFactory; 58 import com.android.systemui.statusbar.connectivity.AccessPointController; 59 import com.android.systemui.statusbar.connectivity.IconState; 60 import com.android.systemui.statusbar.connectivity.MobileDataIndicators; 61 import com.android.systemui.statusbar.connectivity.NetworkController; 62 import com.android.systemui.statusbar.connectivity.SignalCallback; 63 import com.android.systemui.statusbar.connectivity.WifiIcons; 64 import com.android.systemui.statusbar.connectivity.WifiIndicators; 65 66 import java.io.PrintWriter; 67 68 import javax.inject.Inject; 69 70 /** Quick settings tile: Internet **/ 71 public class InternetTile extends QSTileImpl<SignalState> { 72 73 public static final String TILE_SPEC = "internet"; 74 75 private static final Intent WIFI_SETTINGS = new Intent(Settings.ACTION_WIFI_SETTINGS); 76 private static final int LAST_STATE_UNKNOWN = -1; 77 private static final int LAST_STATE_CELLULAR = 0; 78 private static final int LAST_STATE_WIFI = 1; 79 private static final int LAST_STATE_ETHERNET = 2; 80 81 protected final NetworkController mController; 82 private final AccessPointController mAccessPointController; 83 private final DataUsageController mDataController; 84 // The last updated tile state, 0: mobile, 1: wifi, 2: ethernet. 85 private int mLastTileState = LAST_STATE_UNKNOWN; 86 87 protected final InternetSignalCallback mSignalCallback = new InternetSignalCallback(); 88 private final InternetDialogFactory mInternetDialogFactory; 89 final Handler mHandler; 90 91 @Inject InternetTile( QSHost host, QsEventLogger uiEventLogger, @Background Looper backgroundLooper, @Main Handler mainHandler, FalsingManager falsingManager, MetricsLogger metricsLogger, StatusBarStateController statusBarStateController, ActivityStarter activityStarter, QSLogger qsLogger, NetworkController networkController, AccessPointController accessPointController, InternetDialogFactory internetDialogFactory )92 public InternetTile( 93 QSHost host, 94 QsEventLogger uiEventLogger, 95 @Background Looper backgroundLooper, 96 @Main Handler mainHandler, 97 FalsingManager falsingManager, 98 MetricsLogger metricsLogger, 99 StatusBarStateController statusBarStateController, 100 ActivityStarter activityStarter, 101 QSLogger qsLogger, 102 NetworkController networkController, 103 AccessPointController accessPointController, 104 InternetDialogFactory internetDialogFactory 105 ) { 106 super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger, 107 statusBarStateController, activityStarter, qsLogger); 108 mInternetDialogFactory = internetDialogFactory; 109 mHandler = mainHandler; 110 mController = networkController; 111 mAccessPointController = accessPointController; 112 mDataController = mController.getMobileDataController(); 113 mController.observe(getLifecycle(), mSignalCallback); 114 } 115 116 @Override newTileState()117 public SignalState newTileState() { 118 SignalState s = new SignalState(); 119 s.forceExpandIcon = true; 120 return s; 121 } 122 123 @Override createTileView(Context context)124 public QSIconView createTileView(Context context) { 125 return new AlphaControlledSignalTileView(context); 126 } 127 128 @Override getLongClickIntent()129 public Intent getLongClickIntent() { 130 return WIFI_SETTINGS; 131 } 132 133 @Override handleClick(@ullable View view)134 protected void handleClick(@Nullable View view) { 135 mHandler.post(() -> mInternetDialogFactory.create(true, 136 mAccessPointController.canConfigMobileData(), 137 mAccessPointController.canConfigWifi(), view)); 138 } 139 140 @Override getTileLabel()141 public CharSequence getTileLabel() { 142 return mContext.getString(R.string.quick_settings_internet_label); 143 } 144 145 @Override getMetricsCategory()146 public int getMetricsCategory() { 147 return MetricsEvent.QS_WIFI; 148 } 149 150 @Override isAvailable()151 public boolean isAvailable() { 152 return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI) 153 || (mController.hasMobileDataFeature() 154 && mHost.getUserContext().getUserId() == UserHandle.USER_SYSTEM); 155 } 156 157 @Nullable getSecondaryLabel(boolean isTransient, @Nullable String statusLabel)158 private CharSequence getSecondaryLabel(boolean isTransient, @Nullable String statusLabel) { 159 return isTransient 160 ? mContext.getString(R.string.quick_settings_wifi_secondary_label_transient) 161 : statusLabel; 162 } 163 164 @Nullable removeDoubleQuotes(@ullable String string)165 private static String removeDoubleQuotes(@Nullable String string) { 166 if (string == null) return null; 167 final int length = string.length(); 168 if ((length > 1) && (string.charAt(0) == '"') && (string.charAt(length - 1) == '"')) { 169 return string.substring(1, length - 1); 170 } 171 return string; 172 } 173 174 private static final class EthernetCallbackInfo { 175 boolean mConnected; 176 int mEthernetSignalIconId; 177 @Nullable 178 String mEthernetContentDescription; 179 copyTo(EthernetCallbackInfo ethernetCallbackInfo)180 public void copyTo(EthernetCallbackInfo ethernetCallbackInfo) { 181 if (ethernetCallbackInfo == null) { 182 throw new IllegalArgumentException(); 183 } 184 ethernetCallbackInfo.mConnected = this.mConnected; 185 ethernetCallbackInfo.mEthernetSignalIconId = this.mEthernetSignalIconId; 186 ethernetCallbackInfo.mEthernetContentDescription = this.mEthernetContentDescription; 187 } 188 189 @Override toString()190 public String toString() { 191 return new StringBuilder("EthernetCallbackInfo[") 192 .append("mConnected=").append(mConnected) 193 .append(",mEthernetSignalIconId=").append(mEthernetSignalIconId) 194 .append(",mEthernetContentDescription=").append(mEthernetContentDescription) 195 .append(']').toString(); 196 } 197 } 198 199 private static final class WifiCallbackInfo { 200 boolean mAirplaneModeEnabled; 201 boolean mEnabled; 202 boolean mConnected; 203 int mWifiSignalIconId; 204 @Nullable 205 String mSsid; 206 @Nullable 207 String mWifiSignalContentDescription; 208 boolean mIsTransient; 209 @Nullable 210 public String mStatusLabel; 211 boolean mNoDefaultNetwork; 212 boolean mNoValidatedNetwork; 213 boolean mNoNetworksAvailable; 214 copyTo(WifiCallbackInfo wifiCallbackInfo)215 public void copyTo(WifiCallbackInfo wifiCallbackInfo) { 216 if (wifiCallbackInfo == null) { 217 throw new IllegalArgumentException(); 218 } 219 wifiCallbackInfo.mAirplaneModeEnabled = this.mAirplaneModeEnabled; 220 wifiCallbackInfo.mEnabled = this.mEnabled; 221 wifiCallbackInfo.mConnected = this.mConnected; 222 wifiCallbackInfo.mWifiSignalIconId = this.mWifiSignalIconId; 223 wifiCallbackInfo.mSsid = this.mSsid; 224 wifiCallbackInfo.mWifiSignalContentDescription = this.mWifiSignalContentDescription; 225 wifiCallbackInfo.mIsTransient = this.mIsTransient; 226 wifiCallbackInfo.mStatusLabel = this.mStatusLabel; 227 wifiCallbackInfo.mNoDefaultNetwork = this.mNoDefaultNetwork; 228 wifiCallbackInfo.mNoValidatedNetwork = this.mNoValidatedNetwork; 229 wifiCallbackInfo.mNoNetworksAvailable = this.mNoNetworksAvailable; 230 } 231 232 @Override toString()233 public String toString() { 234 return new StringBuilder("WifiCallbackInfo[") 235 .append("mAirplaneModeEnabled=").append(mAirplaneModeEnabled) 236 .append(",mEnabled=").append(mEnabled) 237 .append(",mConnected=").append(mConnected) 238 .append(",mWifiSignalIconId=").append(mWifiSignalIconId) 239 .append(",mSsid=").append(mSsid) 240 .append(",mWifiSignalContentDescription=").append(mWifiSignalContentDescription) 241 .append(",mIsTransient=").append(mIsTransient) 242 .append(",mNoDefaultNetwork=").append(mNoDefaultNetwork) 243 .append(",mNoValidatedNetwork=").append(mNoValidatedNetwork) 244 .append(",mNoNetworksAvailable=").append(mNoNetworksAvailable) 245 .append(']').toString(); 246 } 247 } 248 249 private static final class CellularCallbackInfo { 250 boolean mAirplaneModeEnabled; 251 @Nullable 252 CharSequence mDataSubscriptionName; 253 @Nullable 254 CharSequence mDataContentDescription; 255 int mMobileSignalIconId; 256 int mQsTypeIcon; 257 boolean mNoSim; 258 boolean mRoaming; 259 boolean mMultipleSubs; 260 boolean mNoDefaultNetwork; 261 boolean mNoValidatedNetwork; 262 boolean mNoNetworksAvailable; 263 copyTo(CellularCallbackInfo cellularCallbackInfo)264 public void copyTo(CellularCallbackInfo cellularCallbackInfo) { 265 if (cellularCallbackInfo == null) { 266 throw new IllegalArgumentException(); 267 } 268 cellularCallbackInfo.mAirplaneModeEnabled = this.mAirplaneModeEnabled; 269 cellularCallbackInfo.mDataSubscriptionName = this.mDataSubscriptionName; 270 cellularCallbackInfo.mDataContentDescription = this.mDataContentDescription; 271 cellularCallbackInfo.mMobileSignalIconId = this.mMobileSignalIconId; 272 cellularCallbackInfo.mQsTypeIcon = this.mQsTypeIcon; 273 cellularCallbackInfo.mNoSim = this.mNoSim; 274 cellularCallbackInfo.mRoaming = this.mRoaming; 275 cellularCallbackInfo.mMultipleSubs = this.mMultipleSubs; 276 cellularCallbackInfo.mNoDefaultNetwork = this.mNoDefaultNetwork; 277 cellularCallbackInfo.mNoValidatedNetwork = this.mNoValidatedNetwork; 278 cellularCallbackInfo.mNoNetworksAvailable = this.mNoNetworksAvailable; 279 } 280 281 @Override toString()282 public String toString() { 283 return new StringBuilder("CellularCallbackInfo[") 284 .append("mAirplaneModeEnabled=").append(mAirplaneModeEnabled) 285 .append(",mDataSubscriptionName=").append(mDataSubscriptionName) 286 .append(",mDataContentDescription=").append(mDataContentDescription) 287 .append(",mMobileSignalIconId=").append(mMobileSignalIconId) 288 .append(",mQsTypeIcon=").append(mQsTypeIcon) 289 .append(",mNoSim=").append(mNoSim) 290 .append(",mRoaming=").append(mRoaming) 291 .append(",mMultipleSubs=").append(mMultipleSubs) 292 .append(",mNoDefaultNetwork=").append(mNoDefaultNetwork) 293 .append(",mNoValidatedNetwork=").append(mNoValidatedNetwork) 294 .append(",mNoNetworksAvailable=").append(mNoNetworksAvailable) 295 .append(']').toString(); 296 } 297 } 298 299 protected final class InternetSignalCallback implements SignalCallback { 300 @GuardedBy("mWifiInfo") 301 final WifiCallbackInfo mWifiInfo = new WifiCallbackInfo(); 302 @GuardedBy("mCellularInfo") 303 final CellularCallbackInfo mCellularInfo = new CellularCallbackInfo(); 304 @GuardedBy("mEthernetInfo") 305 final EthernetCallbackInfo mEthernetInfo = new EthernetCallbackInfo(); 306 307 308 @Override setWifiIndicators(@onNull WifiIndicators indicators)309 public void setWifiIndicators(@NonNull WifiIndicators indicators) { 310 if (DEBUG) { 311 Log.d(TAG, "setWifiIndicators: " + indicators); 312 } 313 synchronized (mWifiInfo) { 314 mWifiInfo.mEnabled = indicators.enabled; 315 mWifiInfo.mSsid = indicators.description; 316 mWifiInfo.mIsTransient = indicators.isTransient; 317 mWifiInfo.mStatusLabel = indicators.statusLabel; 318 if (indicators.qsIcon != null) { 319 mWifiInfo.mConnected = indicators.qsIcon.visible; 320 mWifiInfo.mWifiSignalIconId = indicators.qsIcon.icon; 321 mWifiInfo.mWifiSignalContentDescription = indicators.qsIcon.contentDescription; 322 } else { 323 mWifiInfo.mConnected = false; 324 mWifiInfo.mWifiSignalIconId = 0; 325 mWifiInfo.mWifiSignalContentDescription = null; 326 } 327 } 328 if (indicators.qsIcon != null) { 329 refreshState(mWifiInfo); 330 } 331 } 332 333 @Override setMobileDataIndicators(@onNull MobileDataIndicators indicators)334 public void setMobileDataIndicators(@NonNull MobileDataIndicators indicators) { 335 if (DEBUG) { 336 Log.d(TAG, "setMobileDataIndicators: " + indicators); 337 } 338 if (indicators.qsIcon == null) { 339 // Not data sim, don't display. 340 return; 341 } 342 synchronized (mCellularInfo) { 343 mCellularInfo.mDataSubscriptionName = indicators.qsDescription == null 344 ? mController.getMobileDataNetworkName() : indicators.qsDescription; 345 mCellularInfo.mDataContentDescription = indicators.qsDescription != null 346 ? indicators.typeContentDescriptionHtml : null; 347 mCellularInfo.mMobileSignalIconId = indicators.qsIcon.icon; 348 mCellularInfo.mQsTypeIcon = indicators.qsType; 349 mCellularInfo.mRoaming = indicators.roaming; 350 mCellularInfo.mMultipleSubs = mController.getNumberSubscriptions() > 1; 351 } 352 refreshState(mCellularInfo); 353 } 354 355 @Override setEthernetIndicators(@onNull IconState icon)356 public void setEthernetIndicators(@NonNull IconState icon) { 357 if (DEBUG) { 358 Log.d(TAG, "setEthernetIndicators: " 359 + "icon = " + (icon == null ? "" : icon.toString())); 360 } 361 synchronized (mEthernetInfo) { 362 mEthernetInfo.mConnected = icon.visible; 363 mEthernetInfo.mEthernetSignalIconId = icon.icon; 364 mEthernetInfo.mEthernetContentDescription = icon.contentDescription; 365 } 366 if (icon.visible) { 367 refreshState(mEthernetInfo); 368 } 369 } 370 371 @Override setNoSims(boolean show, boolean simDetected)372 public void setNoSims(boolean show, boolean simDetected) { 373 if (DEBUG) { 374 Log.d(TAG, "setNoSims: " 375 + "show = " + show + "," 376 + "simDetected = " + simDetected); 377 } 378 synchronized (mCellularInfo) { 379 mCellularInfo.mNoSim = show; 380 if (mCellularInfo.mNoSim) { 381 // Make sure signal gets cleared out when no sims. 382 mCellularInfo.mMobileSignalIconId = 0; 383 mCellularInfo.mQsTypeIcon = 0; 384 } 385 } 386 } 387 388 @Override setIsAirplaneMode(IconState icon)389 public void setIsAirplaneMode(IconState icon) { 390 if (DEBUG) { 391 Log.d(TAG, "setIsAirplaneMode: " 392 + "icon = " + (icon == null ? "" : icon.toString())); 393 } 394 if (mCellularInfo.mAirplaneModeEnabled == icon.visible) { 395 return; 396 } 397 synchronized (mCellularInfo) { 398 mCellularInfo.mAirplaneModeEnabled = icon.visible; 399 } 400 synchronized (mWifiInfo) { 401 mWifiInfo.mAirplaneModeEnabled = icon.visible; 402 } 403 if (!mSignalCallback.mEthernetInfo.mConnected) { 404 // Always use mWifiInfo to refresh the Internet Tile if airplane mode is enabled, 405 // because Internet Tile will show different information depending on whether WiFi 406 // is enabled or not. 407 if (mWifiInfo.mAirplaneModeEnabled) { 408 refreshState(mWifiInfo); 409 // If airplane mode is disabled, we will use mWifiInfo to refresh the Internet Tile 410 // if WiFi is currently connected to avoid any icon flickering. 411 } else if (mWifiInfo.mEnabled && (mWifiInfo.mWifiSignalIconId > 0) 412 && (mWifiInfo.mSsid != null)) { 413 refreshState(mWifiInfo); 414 } else { 415 refreshState(mCellularInfo); 416 } 417 } 418 } 419 420 @Override setConnectivityStatus(boolean noDefaultNetwork, boolean noValidatedNetwork, boolean noNetworksAvailable)421 public void setConnectivityStatus(boolean noDefaultNetwork, boolean noValidatedNetwork, 422 boolean noNetworksAvailable) { 423 if (DEBUG) { 424 Log.d(TAG, "setConnectivityStatus: " 425 + "noDefaultNetwork = " + noDefaultNetwork + "," 426 + "noValidatedNetwork = " + noValidatedNetwork + "," 427 + "noNetworksAvailable = " + noNetworksAvailable); 428 } 429 synchronized (mCellularInfo) { 430 mCellularInfo.mNoDefaultNetwork = noDefaultNetwork; 431 mCellularInfo.mNoValidatedNetwork = noValidatedNetwork; 432 mCellularInfo.mNoNetworksAvailable = noNetworksAvailable; 433 } 434 synchronized (mWifiInfo) { 435 mWifiInfo.mNoDefaultNetwork = noDefaultNetwork; 436 mWifiInfo.mNoValidatedNetwork = noValidatedNetwork; 437 mWifiInfo.mNoNetworksAvailable = noNetworksAvailable; 438 } 439 if (!noDefaultNetwork) { 440 return; 441 } 442 refreshState(mWifiInfo); 443 } 444 445 @Override toString()446 public String toString() { 447 return new StringBuilder("InternetSignalCallback[") 448 .append("mWifiInfo=").append(mWifiInfo) 449 .append(",mCellularInfo=").append(mCellularInfo) 450 .append(",mEthernetInfo=").append(mEthernetInfo) 451 .append(']').toString(); 452 } 453 } 454 455 @Override handleUpdateState(SignalState state, Object arg)456 protected void handleUpdateState(SignalState state, Object arg) { 457 mQSLogger.logInternetTileUpdate( 458 getTileSpec(), mLastTileState, arg == null ? "null" : arg.toString()); 459 if (arg instanceof CellularCallbackInfo) { 460 mLastTileState = LAST_STATE_CELLULAR; 461 CellularCallbackInfo cb = (CellularCallbackInfo) arg; 462 CellularCallbackInfo cellularInfo = new CellularCallbackInfo(); 463 synchronized (cb) { 464 cb.copyTo(cellularInfo); 465 } 466 handleUpdateCellularState(state, cellularInfo); 467 } else if (arg instanceof WifiCallbackInfo) { 468 mLastTileState = LAST_STATE_WIFI; 469 WifiCallbackInfo cb = (WifiCallbackInfo) arg; 470 WifiCallbackInfo wifiInfo = new WifiCallbackInfo(); 471 synchronized (cb) { 472 cb.copyTo(wifiInfo); 473 } 474 handleUpdateWifiState(state, wifiInfo); 475 } else if (arg instanceof EthernetCallbackInfo) { 476 mLastTileState = LAST_STATE_ETHERNET; 477 EthernetCallbackInfo cb = (EthernetCallbackInfo) arg; 478 EthernetCallbackInfo ethernetInfo = new EthernetCallbackInfo(); 479 synchronized (cb) { 480 cb.copyTo(ethernetInfo); 481 } 482 handleUpdateEthernetState(state, ethernetInfo); 483 } else { 484 // handleUpdateState will be triggered when user expands the QuickSetting panel with 485 // arg = null, in this case the last updated CellularCallbackInfo or WifiCallbackInfo 486 // should be used to refresh the tile. 487 if (mLastTileState == LAST_STATE_CELLULAR) { 488 CellularCallbackInfo cellularInfo = new CellularCallbackInfo(); 489 synchronized (mSignalCallback.mCellularInfo) { 490 mSignalCallback.mCellularInfo.copyTo(cellularInfo); 491 } 492 handleUpdateCellularState(state, cellularInfo); 493 } else if (mLastTileState == LAST_STATE_WIFI) { 494 WifiCallbackInfo wifiInfo = new WifiCallbackInfo(); 495 synchronized (mSignalCallback.mWifiInfo) { 496 mSignalCallback.mWifiInfo.copyTo(wifiInfo); 497 } 498 handleUpdateWifiState(state, wifiInfo); 499 } else if (mLastTileState == LAST_STATE_ETHERNET) { 500 EthernetCallbackInfo ethernetInfo = new EthernetCallbackInfo(); 501 synchronized (mSignalCallback.mEthernetInfo) { 502 mSignalCallback.mEthernetInfo.copyTo(ethernetInfo); 503 } 504 handleUpdateEthernetState(state, ethernetInfo); 505 } 506 } 507 } 508 handleUpdateWifiState(SignalState state, Object arg)509 private void handleUpdateWifiState(SignalState state, Object arg) { 510 WifiCallbackInfo cb = (WifiCallbackInfo) arg; 511 if (DEBUG) { 512 Log.d(TAG, "handleUpdateWifiState: " + "WifiCallbackInfo = " + cb.toString()); 513 } 514 boolean wifiConnected = cb.mEnabled && (cb.mWifiSignalIconId > 0) && (cb.mSsid != null); 515 boolean wifiNotConnected = (cb.mWifiSignalIconId > 0) && (cb.mSsid == null); 516 if (state.slash == null) { 517 state.slash = new SlashState(); 518 state.slash.rotation = 6; 519 } 520 state.slash.isSlashed = false; 521 state.secondaryLabel = getSecondaryLabel(cb.mIsTransient, removeDoubleQuotes(cb.mSsid)); 522 state.state = Tile.STATE_ACTIVE; 523 state.dualTarget = true; 524 state.value = cb.mEnabled; 525 final StringBuffer minimalContentDescription = new StringBuffer(); 526 final StringBuffer minimalStateDescription = new StringBuffer(); 527 final Resources r = mContext.getResources(); 528 state.label = r.getString(R.string.quick_settings_internet_label); 529 if (cb.mAirplaneModeEnabled) { 530 if (!state.value) { 531 state.state = Tile.STATE_INACTIVE; 532 state.icon = ResourceIcon.get(R.drawable.ic_qs_no_internet_unavailable); 533 state.secondaryLabel = r.getString(R.string.status_bar_airplane); 534 } else if (!wifiConnected) { 535 state.icon = ResourceIcon.get(R.drawable.ic_qs_no_internet_unavailable); 536 if (cb.mNoNetworksAvailable) { 537 state.secondaryLabel = 538 r.getString(R.string.quick_settings_networks_unavailable); 539 } else { 540 state.secondaryLabel = 541 r.getString(R.string.quick_settings_networks_available); 542 } 543 } else { 544 state.icon = ResourceIcon.get(cb.mWifiSignalIconId); 545 } 546 } else if (cb.mNoDefaultNetwork) { 547 if (cb.mNoNetworksAvailable || !cb.mEnabled) { 548 state.icon = ResourceIcon.get(R.drawable.ic_qs_no_internet_unavailable); 549 state.secondaryLabel = r.getString(R.string.quick_settings_networks_unavailable); 550 } else { 551 state.icon = ResourceIcon.get(R.drawable.ic_qs_no_internet_available); 552 state.secondaryLabel = r.getString(R.string.quick_settings_networks_available); 553 } 554 } else if (cb.mIsTransient) { 555 state.icon = ResourceIcon.get( 556 com.android.internal.R.drawable.ic_signal_wifi_transient_animation); 557 } else if (!state.value) { 558 state.slash.isSlashed = true; 559 state.state = Tile.STATE_INACTIVE; 560 state.icon = ResourceIcon.get(WifiIcons.QS_WIFI_DISABLED); 561 } else if (wifiConnected) { 562 state.icon = ResourceIcon.get(cb.mWifiSignalIconId); 563 } else if (wifiNotConnected) { 564 state.icon = ResourceIcon.get(WifiIcons.QS_WIFI_NO_NETWORK); 565 } else { 566 state.icon = ResourceIcon.get(WifiIcons.QS_WIFI_NO_NETWORK); 567 } 568 minimalContentDescription.append( 569 mContext.getString(R.string.quick_settings_internet_label)).append(","); 570 if (state.value && wifiConnected) { 571 minimalStateDescription.append(cb.mWifiSignalContentDescription); 572 minimalContentDescription.append(removeDoubleQuotes(cb.mSsid)); 573 } else if (!TextUtils.isEmpty(state.secondaryLabel)) { 574 minimalContentDescription.append(",").append(state.secondaryLabel); 575 } 576 577 state.stateDescription = minimalStateDescription.toString(); 578 state.contentDescription = minimalContentDescription.toString(); 579 state.dualLabelContentDescription = r.getString( 580 R.string.accessibility_quick_settings_open_settings, getTileLabel()); 581 state.expandedAccessibilityClassName = Switch.class.getName(); 582 if (DEBUG) { 583 Log.d(TAG, "handleUpdateWifiState: " + "SignalState = " + state.toString()); 584 } 585 } 586 handleUpdateCellularState(SignalState state, Object arg)587 private void handleUpdateCellularState(SignalState state, Object arg) { 588 CellularCallbackInfo cb = (CellularCallbackInfo) arg; 589 if (DEBUG) { 590 Log.d(TAG, "handleUpdateCellularState: " + "CellularCallbackInfo = " + cb.toString()); 591 } 592 final Resources r = mContext.getResources(); 593 state.label = r.getString(R.string.quick_settings_internet_label); 594 state.state = Tile.STATE_ACTIVE; 595 boolean mobileDataEnabled = mDataController.isMobileDataSupported() 596 && mDataController.isMobileDataEnabled(); 597 state.value = mobileDataEnabled; 598 state.expandedAccessibilityClassName = Switch.class.getName(); 599 600 if (cb.mAirplaneModeEnabled && cb.mQsTypeIcon != TelephonyIcons.ICON_CWF) { 601 state.state = Tile.STATE_INACTIVE; 602 state.icon = ResourceIcon.get(R.drawable.ic_qs_no_internet_unavailable); 603 state.secondaryLabel = r.getString(R.string.status_bar_airplane); 604 } else if (cb.mNoDefaultNetwork) { 605 if (cb.mNoNetworksAvailable || !mSignalCallback.mWifiInfo.mEnabled) { 606 state.icon = ResourceIcon.get(R.drawable.ic_qs_no_internet_unavailable); 607 state.secondaryLabel = r.getString(R.string.quick_settings_networks_unavailable); 608 } else { 609 state.icon = ResourceIcon.get(R.drawable.ic_qs_no_internet_available); 610 state.secondaryLabel = r.getString(R.string.quick_settings_networks_available); 611 } 612 } else { 613 state.icon = new SignalIcon(cb.mMobileSignalIconId); 614 state.secondaryLabel = appendMobileDataType(cb.mDataSubscriptionName, 615 getMobileDataContentName(cb)); 616 } 617 618 state.contentDescription = state.label; 619 if (state.state == Tile.STATE_INACTIVE) { 620 // This information is appended later by converting the Tile.STATE_INACTIVE state. 621 state.stateDescription = ""; 622 } else { 623 state.stateDescription = state.secondaryLabel; 624 } 625 if (DEBUG) { 626 Log.d(TAG, "handleUpdateCellularState: " + "SignalState = " + state.toString()); 627 } 628 } 629 handleUpdateEthernetState(SignalState state, Object arg)630 private void handleUpdateEthernetState(SignalState state, Object arg) { 631 EthernetCallbackInfo cb = (EthernetCallbackInfo) arg; 632 if (DEBUG) { 633 Log.d(TAG, "handleUpdateEthernetState: " + "EthernetCallbackInfo = " + cb.toString()); 634 } 635 if (!cb.mConnected) { 636 return; 637 } 638 final Resources r = mContext.getResources(); 639 state.label = r.getString(R.string.quick_settings_internet_label); 640 state.state = Tile.STATE_ACTIVE; 641 state.icon = ResourceIcon.get(cb.mEthernetSignalIconId); 642 state.secondaryLabel = cb.mEthernetContentDescription; 643 if (DEBUG) { 644 Log.d(TAG, "handleUpdateEthernetState: " + "SignalState = " + state.toString()); 645 } 646 } 647 appendMobileDataType( @ullable CharSequence current, @Nullable CharSequence dataType)648 private CharSequence appendMobileDataType( 649 @Nullable CharSequence current, @Nullable CharSequence dataType) { 650 if (TextUtils.isEmpty(dataType)) { 651 return Html.fromHtml((current == null ? "" : current.toString()), 0); 652 } 653 if (TextUtils.isEmpty(current)) { 654 return Html.fromHtml((dataType == null ? "" : dataType.toString()), 0); 655 } 656 String concat = mContext.getString(R.string.mobile_carrier_text_format, current, dataType); 657 return Html.fromHtml(concat, 0); 658 } 659 660 @Nullable getMobileDataContentName(CellularCallbackInfo cb)661 private CharSequence getMobileDataContentName(CellularCallbackInfo cb) { 662 if (cb.mRoaming && !TextUtils.isEmpty(cb.mDataContentDescription)) { 663 String roaming = mContext.getString(R.string.data_connection_roaming); 664 String dataDescription = 665 cb.mDataContentDescription == null ? "" 666 : cb.mDataContentDescription.toString(); 667 return mContext.getString(R.string.mobile_data_text_format, roaming, dataDescription); 668 } 669 if (cb.mRoaming) { 670 return mContext.getString(R.string.data_connection_roaming); 671 } 672 return cb.mDataContentDescription; 673 } 674 675 private static class SignalIcon extends Icon { 676 private final int mState; SignalIcon(int state)677 SignalIcon(int state) { 678 mState = state; 679 } getState()680 public int getState() { 681 return mState; 682 } 683 684 @Override 685 @NonNull getDrawable(Context context)686 public Drawable getDrawable(Context context) { 687 SignalDrawable d = new SignalDrawable(context); 688 d.setLevel(getState()); 689 return d; 690 } 691 @Override toString()692 public String toString() { 693 return String.format("SignalIcon[mState=0x%08x]", mState); 694 } 695 } 696 697 /** 698 * Dumps the state of this tile along with its name. 699 */ 700 @Override dump(PrintWriter pw, String[] args)701 public void dump(PrintWriter pw, String[] args) { 702 pw.println(this.getClass().getSimpleName() + ":"); 703 pw.print(" "); pw.println(getState().toString()); 704 pw.print(" "); pw.println("mLastTileState=" + mLastTileState); 705 pw.print(" "); pw.println("mSignalCallback=" + mSignalCallback.toString()); 706 } 707 708 // For testing usage only. getLastTileState()709 protected int getLastTileState() { 710 return mLastTileState; 711 } 712 } 713