1 /* 2 * Copyright (C) 2015 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 package com.android.systemui.statusbar.connectivity; 17 18 import static android.telephony.TelephonyManager.UNKNOWN_CARRIER_ID; 19 20 import android.content.Context; 21 import android.content.Intent; 22 import android.database.ContentObserver; 23 import android.net.NetworkCapabilities; 24 import android.os.Handler; 25 import android.os.Looper; 26 import android.provider.Settings.Global; 27 import android.telephony.CellSignalStrength; 28 import android.telephony.CellSignalStrengthCdma; 29 import android.telephony.SignalStrength; 30 import android.telephony.SubscriptionInfo; 31 import android.telephony.SubscriptionManager; 32 import android.telephony.TelephonyManager; 33 import android.text.Html; 34 import android.text.TextUtils; 35 import android.util.Log; 36 37 import com.android.internal.annotations.VisibleForTesting; 38 import com.android.settingslib.SignalIcon.MobileIconGroup; 39 import com.android.settingslib.graph.SignalDrawable; 40 import com.android.settingslib.mobile.MobileMappings.Config; 41 import com.android.settingslib.mobile.MobileStatusTracker; 42 import com.android.settingslib.mobile.MobileStatusTracker.MobileStatus; 43 import com.android.settingslib.mobile.MobileStatusTracker.SubscriptionDefaults; 44 import com.android.settingslib.mobile.TelephonyIcons; 45 import com.android.settingslib.net.SignalStrengthUtil; 46 import com.android.systemui.res.R; 47 import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy; 48 import com.android.systemui.util.CarrierConfigTracker; 49 50 import java.io.PrintWriter; 51 import java.text.SimpleDateFormat; 52 import java.util.BitSet; 53 import java.util.List; 54 import java.util.Map; 55 56 /** 57 * Monitors the mobile signal changes and update the SysUI icons. 58 */ 59 public class MobileSignalController extends SignalController<MobileState, MobileIconGroup> { 60 private static final SimpleDateFormat SSDF = new SimpleDateFormat("MM-dd HH:mm:ss.SSS"); 61 private static final int STATUS_HISTORY_SIZE = 64; 62 private final TelephonyManager mPhone; 63 private final CarrierConfigTracker mCarrierConfigTracker; 64 private final SubscriptionDefaults mDefaults; 65 private final MobileMappingsProxy mMobileMappingsProxy; 66 private final String mNetworkNameDefault; 67 private final String mNetworkNameSeparator; 68 private final ContentObserver mObserver; 69 // Save entire info for logging, we only use the id. 70 final SubscriptionInfo mSubscriptionInfo; 71 private Map<String, MobileIconGroup> mNetworkToIconLookup; 72 73 private MobileIconGroup mDefaultIcons; 74 private Config mConfig; 75 @VisibleForTesting 76 boolean mInflateSignalStrengths = false; 77 @VisibleForTesting 78 final MobileStatusTracker mMobileStatusTracker; 79 80 // Save the previous STATUS_HISTORY_SIZE states for logging. 81 private final String[] mMobileStatusHistory = new String[STATUS_HISTORY_SIZE]; 82 // Where to copy the next state into. 83 private int mMobileStatusHistoryIndex; 84 85 private final MobileStatusTracker.Callback mMobileCallback = 86 new MobileStatusTracker.Callback() { 87 private String mLastStatus; 88 89 @Override 90 public void onMobileStatusChanged(boolean updateTelephony, 91 MobileStatus mobileStatus) { 92 if (DEBUG) { 93 Log.d(mTag, "onMobileStatusChanged=" 94 + " updateTelephony=" + updateTelephony 95 + " mobileStatus=" + mobileStatus.toString()); 96 } 97 String currentStatus = mobileStatus.toString(); 98 if (!currentStatus.equals(mLastStatus)) { 99 mLastStatus = currentStatus; 100 String status = new StringBuilder() 101 .append(SSDF.format(System.currentTimeMillis())).append(",") 102 .append(currentStatus) 103 .toString(); 104 recordLastMobileStatus(status); 105 } 106 updateMobileStatus(mobileStatus); 107 if (updateTelephony) { 108 updateTelephony(); 109 } else { 110 notifyListenersIfNecessary(); 111 } 112 } 113 }; 114 115 // TODO: Reduce number of vars passed in, if we have the NetworkController, probably don't 116 // need listener lists anymore. MobileSignalController( Context context, Config config, boolean hasMobileData, TelephonyManager phone, CallbackHandler callbackHandler, NetworkControllerImpl networkController, MobileMappingsProxy mobileMappingsProxy, SubscriptionInfo info, SubscriptionDefaults defaults, Looper receiverLooper, CarrierConfigTracker carrierConfigTracker, MobileStatusTrackerFactory mobileStatusTrackerFactory )117 public MobileSignalController( 118 Context context, 119 Config config, 120 boolean hasMobileData, 121 TelephonyManager phone, 122 CallbackHandler callbackHandler, 123 NetworkControllerImpl networkController, 124 MobileMappingsProxy mobileMappingsProxy, 125 SubscriptionInfo info, 126 SubscriptionDefaults defaults, 127 Looper receiverLooper, 128 CarrierConfigTracker carrierConfigTracker, 129 MobileStatusTrackerFactory mobileStatusTrackerFactory 130 ) { 131 super("MobileSignalController(" + info.getSubscriptionId() + ")", context, 132 NetworkCapabilities.TRANSPORT_CELLULAR, callbackHandler, 133 networkController); 134 mCarrierConfigTracker = carrierConfigTracker; 135 mConfig = config; 136 mPhone = phone; 137 mDefaults = defaults; 138 mSubscriptionInfo = info; 139 mMobileMappingsProxy = mobileMappingsProxy; 140 mNetworkNameSeparator = getTextIfExists( 141 R.string.status_bar_network_name_separator).toString(); 142 mNetworkNameDefault = getTextIfExists( 143 com.android.internal.R.string.lockscreen_carrier_default).toString(); 144 145 mNetworkToIconLookup = mMobileMappingsProxy.mapIconSets(mConfig); 146 mDefaultIcons = mMobileMappingsProxy.getDefaultIcons(mConfig); 147 148 String networkName = info.getCarrierName() != null ? info.getCarrierName().toString() 149 : mNetworkNameDefault; 150 mLastState.networkName = mCurrentState.networkName = networkName; 151 mLastState.networkNameData = mCurrentState.networkNameData = networkName; 152 mLastState.enabled = mCurrentState.enabled = hasMobileData; 153 mLastState.iconGroup = mCurrentState.iconGroup = mDefaultIcons; 154 mObserver = new ContentObserver(new Handler(receiverLooper)) { 155 @Override 156 public void onChange(boolean selfChange) { 157 updateTelephony(); 158 } 159 }; 160 mMobileStatusTracker = mobileStatusTrackerFactory.createTracker(mMobileCallback); 161 } 162 setConfiguration(Config config)163 void setConfiguration(Config config) { 164 mConfig = config; 165 updateInflateSignalStrength(); 166 mNetworkToIconLookup = mMobileMappingsProxy.mapIconSets(mConfig); 167 mDefaultIcons = mMobileMappingsProxy.getDefaultIcons(mConfig); 168 updateTelephony(); 169 } 170 setAirplaneMode(boolean airplaneMode)171 void setAirplaneMode(boolean airplaneMode) { 172 mCurrentState.airplaneMode = airplaneMode; 173 notifyListenersIfNecessary(); 174 } 175 setUserSetupComplete(boolean userSetup)176 void setUserSetupComplete(boolean userSetup) { 177 mCurrentState.userSetup = userSetup; 178 notifyListenersIfNecessary(); 179 } 180 181 @Override updateConnectivity(BitSet connectedTransports, BitSet validatedTransports)182 public void updateConnectivity(BitSet connectedTransports, BitSet validatedTransports) { 183 boolean isValidated = validatedTransports.get(mTransportType); 184 mCurrentState.isDefault = connectedTransports.get(mTransportType); 185 // Only show this as not having connectivity if we are default. 186 mCurrentState.inetCondition = (isValidated || !mCurrentState.isDefault) ? 1 : 0; 187 notifyListenersIfNecessary(); 188 } 189 setCarrierNetworkChangeMode(boolean carrierNetworkChangeMode)190 void setCarrierNetworkChangeMode(boolean carrierNetworkChangeMode) { 191 mCurrentState.carrierNetworkChangeMode = carrierNetworkChangeMode; 192 updateTelephony(); 193 } 194 195 /** 196 * Start listening for phone state changes. 197 */ registerListener()198 public void registerListener() { 199 mMobileStatusTracker.setListening(true); 200 mContext.getContentResolver().registerContentObserver(Global.getUriFor(Global.MOBILE_DATA), 201 true, mObserver); 202 mContext.getContentResolver().registerContentObserver(Global.getUriFor( 203 Global.MOBILE_DATA + mSubscriptionInfo.getSubscriptionId()), 204 true, mObserver); 205 } 206 207 /** 208 * Stop listening for phone state changes. 209 */ unregisterListener()210 public void unregisterListener() { 211 mMobileStatusTracker.setListening(false); 212 mContext.getContentResolver().unregisterContentObserver(mObserver); 213 } 214 updateInflateSignalStrength()215 private void updateInflateSignalStrength() { 216 mInflateSignalStrengths = SignalStrengthUtil.shouldInflateSignalStrength(mContext, 217 mSubscriptionInfo.getSubscriptionId()); 218 } 219 getNumLevels()220 private int getNumLevels() { 221 if (mInflateSignalStrengths) { 222 return CellSignalStrength.getNumSignalStrengthLevels() + 1; 223 } 224 return CellSignalStrength.getNumSignalStrengthLevels(); 225 } 226 227 @Override getCurrentIconId()228 public int getCurrentIconId() { 229 if (mCurrentState.iconGroup == TelephonyIcons.CARRIER_NETWORK_CHANGE) { 230 return SignalDrawable.getCarrierChangeState(getNumLevels()); 231 } else if (mCurrentState.connected) { 232 int level = mCurrentState.level; 233 if (mInflateSignalStrengths) { 234 level++; 235 } 236 boolean dataDisabled = mCurrentState.userSetup 237 && (mCurrentState.iconGroup == TelephonyIcons.DATA_DISABLED 238 || (mCurrentState.iconGroup == TelephonyIcons.NOT_DEFAULT_DATA 239 && mCurrentState.defaultDataOff)); 240 boolean noInternet = mCurrentState.inetCondition == 0; 241 boolean cutOut = dataDisabled || noInternet; 242 return SignalDrawable.getState(level, getNumLevels(), cutOut); 243 } else if (mCurrentState.enabled) { 244 return SignalDrawable.getEmptyState(getNumLevels()); 245 } else { 246 return 0; 247 } 248 } 249 250 @Override getQsCurrentIconId()251 public int getQsCurrentIconId() { 252 return getCurrentIconId(); 253 } 254 255 @Override notifyListeners(SignalCallback callback)256 public void notifyListeners(SignalCallback callback) { 257 // If the device is on carrier merged WiFi, we should let WifiSignalController to control 258 // the SysUI states. 259 if (mNetworkController.isCarrierMergedWifi(mSubscriptionInfo.getSubscriptionId())) { 260 return; 261 } 262 MobileIconGroup icons = getIcons(); 263 264 String contentDescription = getTextIfExists(getContentDescription()).toString(); 265 CharSequence dataContentDescriptionHtml = getTextIfExists(icons.dataContentDescription); 266 267 //TODO: Hacky 268 // The data content description can sometimes be shown in a text view and might come to us 269 // as HTML. Strip any styling here so that listeners don't have to care 270 CharSequence dataContentDescription = Html.fromHtml( 271 dataContentDescriptionHtml.toString(), 0).toString(); 272 if (mCurrentState.inetCondition == 0) { 273 dataContentDescription = mContext.getString(R.string.data_connection_no_internet); 274 } 275 276 int iconId = mCurrentState.getNetworkTypeIcon(mContext); 277 final QsInfo qsInfo = getQsInfo(contentDescription, iconId); 278 final SbInfo sbInfo = getSbInfo(contentDescription, iconId); 279 280 MobileDataIndicators mobileDataIndicators = new MobileDataIndicators( 281 sbInfo.icon, 282 qsInfo.icon, 283 sbInfo.ratTypeIcon, 284 qsInfo.ratTypeIcon, 285 mCurrentState.hasActivityIn(), 286 mCurrentState.hasActivityOut(), 287 dataContentDescription, 288 dataContentDescriptionHtml, 289 qsInfo.description, 290 mSubscriptionInfo.getSubscriptionId(), 291 mCurrentState.roaming, 292 sbInfo.showTriangle); 293 callback.setMobileDataIndicators(mobileDataIndicators); 294 } 295 getQsInfo(String contentDescription, int dataTypeIcon)296 private QsInfo getQsInfo(String contentDescription, int dataTypeIcon) { 297 int qsTypeIcon = 0; 298 IconState qsIcon = null; 299 CharSequence qsDescription = null; 300 301 if (mCurrentState.dataSim) { 302 // only show QS icons if the state is also default 303 if (!mCurrentState.isDefault) { 304 return new QsInfo(qsTypeIcon, qsIcon, qsDescription); 305 } 306 307 if (mCurrentState.showQuickSettingsRatIcon() || mConfig.alwaysShowDataRatIcon) { 308 qsTypeIcon = dataTypeIcon; 309 } 310 311 boolean qsIconVisible = mCurrentState.enabled && !mCurrentState.isEmergency; 312 qsIcon = new IconState(qsIconVisible, getQsCurrentIconId(), contentDescription); 313 314 if (!mCurrentState.isEmergency) { 315 qsDescription = mCurrentState.networkName; 316 } 317 } 318 319 return new QsInfo(qsTypeIcon, qsIcon, qsDescription); 320 } 321 getSbInfo(String contentDescription, int dataTypeIcon)322 private SbInfo getSbInfo(String contentDescription, int dataTypeIcon) { 323 final boolean dataDisabled = mCurrentState.isDataDisabledOrNotDefault(); 324 IconState statusIcon = new IconState( 325 mCurrentState.enabled && !mCurrentState.airplaneMode, 326 getCurrentIconId(), contentDescription); 327 328 boolean showDataIconInStatusBar = 329 (mCurrentState.dataConnected && mCurrentState.isDefault) || dataDisabled; 330 int typeIcon = 331 (showDataIconInStatusBar || mConfig.alwaysShowDataRatIcon) ? dataTypeIcon : 0; 332 boolean showTriangle = mCurrentState.enabled && !mCurrentState.airplaneMode; 333 334 return new SbInfo(showTriangle, typeIcon, statusIcon); 335 } 336 337 @Override cleanState()338 protected MobileState cleanState() { 339 return new MobileState(); 340 } 341 isInService()342 public boolean isInService() { 343 return mCurrentState.isInService(); 344 } 345 getNetworkNameForCarrierWiFi()346 String getNetworkNameForCarrierWiFi() { 347 return mPhone.getSimOperatorName(); 348 } 349 isRoaming()350 private boolean isRoaming() { 351 // During a carrier change, roaming indications need to be suppressed. 352 if (isCarrierNetworkChangeActive()) { 353 return false; 354 } 355 if (mCurrentState.isCdma()) { 356 return mPhone.getCdmaEnhancedRoamingIndicatorDisplayNumber() 357 != TelephonyManager.ERI_OFF; 358 } else { 359 return mCurrentState.isRoaming(); 360 } 361 } 362 isCarrierNetworkChangeActive()363 private boolean isCarrierNetworkChangeActive() { 364 return mCurrentState.carrierNetworkChangeMode; 365 } 366 handleBroadcast(Intent intent)367 void handleBroadcast(Intent intent) { 368 String action = intent.getAction(); 369 if (action.equals(TelephonyManager.ACTION_SERVICE_PROVIDERS_UPDATED)) { 370 updateNetworkName(intent.getBooleanExtra(TelephonyManager.EXTRA_SHOW_SPN, false), 371 intent.getStringExtra(TelephonyManager.EXTRA_SPN), 372 intent.getStringExtra(TelephonyManager.EXTRA_DATA_SPN), 373 intent.getBooleanExtra(TelephonyManager.EXTRA_SHOW_PLMN, false), 374 intent.getStringExtra(TelephonyManager.EXTRA_PLMN)); 375 notifyListenersIfNecessary(); 376 } else if (action.equals(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)) { 377 updateDataSim(); 378 notifyListenersIfNecessary(); 379 } else if (action.equals(TelephonyManager.ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED)) { 380 int carrierId = intent.getIntExtra( 381 TelephonyManager.EXTRA_CARRIER_ID, UNKNOWN_CARRIER_ID); 382 mCurrentState.setCarrierId(carrierId); 383 } 384 } 385 updateDataSim()386 private void updateDataSim() { 387 int activeDataSubId = mDefaults.getActiveDataSubId(); 388 if (SubscriptionManager.isValidSubscriptionId(activeDataSubId)) { 389 mCurrentState.dataSim = activeDataSubId == mSubscriptionInfo.getSubscriptionId(); 390 } else { 391 // There doesn't seem to be a data sim selected, however if 392 // there isn't a MobileSignalController with dataSim set, then 393 // QS won't get any callbacks and will be blank. Instead 394 // lets just assume we are the data sim (which will basically 395 // show one at random) in QS until one is selected. The user 396 // should pick one soon after, so we shouldn't be in this state 397 // for long. 398 mCurrentState.dataSim = true; 399 } 400 } 401 402 /** 403 * Updates the network's name based on incoming spn and plmn. 404 */ updateNetworkName(boolean showSpn, String spn, String dataSpn, boolean showPlmn, String plmn)405 void updateNetworkName(boolean showSpn, String spn, String dataSpn, 406 boolean showPlmn, String plmn) { 407 if (CHATTY) { 408 Log.d("CarrierLabel", "updateNetworkName showSpn=" + showSpn 409 + " spn=" + spn + " dataSpn=" + dataSpn 410 + " showPlmn=" + showPlmn + " plmn=" + plmn); 411 } 412 StringBuilder str = new StringBuilder(); 413 StringBuilder strData = new StringBuilder(); 414 if (showPlmn && plmn != null) { 415 str.append(plmn); 416 strData.append(plmn); 417 } 418 if (showSpn && spn != null) { 419 if (str.length() != 0) { 420 str.append(mNetworkNameSeparator); 421 } 422 str.append(spn); 423 } 424 if (str.length() != 0) { 425 mCurrentState.networkName = str.toString(); 426 } else { 427 mCurrentState.networkName = mNetworkNameDefault; 428 } 429 if (showSpn && dataSpn != null) { 430 if (strData.length() != 0) { 431 strData.append(mNetworkNameSeparator); 432 } 433 strData.append(dataSpn); 434 } 435 if (strData.length() != 0) { 436 mCurrentState.networkNameData = strData.toString(); 437 } else { 438 mCurrentState.networkNameData = mNetworkNameDefault; 439 } 440 } 441 442 /** 443 * Extracts the CellSignalStrengthCdma from SignalStrength then returns the level 444 */ getCdmaLevel(SignalStrength signalStrength)445 private int getCdmaLevel(SignalStrength signalStrength) { 446 List<CellSignalStrengthCdma> signalStrengthCdma = 447 signalStrength.getCellSignalStrengths(CellSignalStrengthCdma.class); 448 if (!signalStrengthCdma.isEmpty()) { 449 return signalStrengthCdma.get(0).getLevel(); 450 } 451 return CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN; 452 } 453 updateMobileStatus(MobileStatus mobileStatus)454 private void updateMobileStatus(MobileStatus mobileStatus) { 455 mCurrentState.setFromMobileStatus(mobileStatus); 456 } 457 getSignalLevel(SignalStrength signalStrength)458 int getSignalLevel(SignalStrength signalStrength) { 459 if (signalStrength == null) { 460 return 0; 461 } 462 if (!signalStrength.isGsm() && mConfig.alwaysShowCdmaRssi) { 463 return getCdmaLevel(signalStrength); 464 } else { 465 return signalStrength.getLevel(); 466 } 467 } 468 469 /** 470 * Updates the current state based on ServiceState, SignalStrength, DataState, 471 * TelephonyDisplayInfo, and sim state. It should be called any time one of these is updated. 472 * This will call listeners if necessary. 473 */ updateTelephony()474 private void updateTelephony() { 475 if (DEBUG) { 476 Log.d(mTag, "updateTelephonySignalStrength: hasService=" 477 + mCurrentState.isInService() 478 + " ss=" + mCurrentState.signalStrength 479 + " displayInfo=" + mCurrentState.telephonyDisplayInfo); 480 } 481 checkDefaultData(); 482 mCurrentState.connected = mCurrentState.isInService(); 483 if (mCurrentState.connected) { 484 mCurrentState.level = getSignalLevel(mCurrentState.signalStrength); 485 } 486 487 mCurrentState.setCarrierId(mPhone.getSimCarrierId()); 488 String iconKey = mMobileMappingsProxy.getIconKey(mCurrentState.telephonyDisplayInfo); 489 if (mNetworkToIconLookup.get(iconKey) != null) { 490 mCurrentState.iconGroup = mNetworkToIconLookup.get(iconKey); 491 } else { 492 mCurrentState.iconGroup = mDefaultIcons; 493 } 494 mCurrentState.dataConnected = mCurrentState.isDataConnected(); 495 496 mCurrentState.roaming = isRoaming(); 497 if (isCarrierNetworkChangeActive()) { 498 mCurrentState.iconGroup = TelephonyIcons.CARRIER_NETWORK_CHANGE; 499 } else if (isDataDisabled() && !mConfig.alwaysShowDataRatIcon) { 500 if (mSubscriptionInfo.getSubscriptionId() != mDefaults.getDefaultDataSubId()) { 501 mCurrentState.iconGroup = TelephonyIcons.NOT_DEFAULT_DATA; 502 } else { 503 mCurrentState.iconGroup = TelephonyIcons.DATA_DISABLED; 504 } 505 } 506 if (mCurrentState.isEmergencyOnly() != mCurrentState.isEmergency) { 507 mCurrentState.isEmergency = mCurrentState.isEmergencyOnly(); 508 mNetworkController.recalculateEmergency(); 509 } 510 // Fill in the network name if we think we have it. 511 if (mCurrentState.networkName.equals(mNetworkNameDefault) 512 && !TextUtils.isEmpty(mCurrentState.getOperatorAlphaShort())) { 513 mCurrentState.networkName = mCurrentState.getOperatorAlphaShort(); 514 } 515 // If this is the data subscription, update the currentState data name 516 if (mCurrentState.networkNameData.equals(mNetworkNameDefault) 517 && mCurrentState.dataSim 518 && !TextUtils.isEmpty(mCurrentState.getOperatorAlphaShort())) { 519 mCurrentState.networkNameData = mCurrentState.getOperatorAlphaShort(); 520 } 521 522 notifyListenersIfNecessary(); 523 } 524 525 /** 526 * If we are controlling the NOT_DEFAULT_DATA icon, check the status of the other one 527 */ checkDefaultData()528 private void checkDefaultData() { 529 if (mCurrentState.iconGroup != TelephonyIcons.NOT_DEFAULT_DATA) { 530 mCurrentState.defaultDataOff = false; 531 return; 532 } 533 534 mCurrentState.defaultDataOff = mNetworkController.isDataControllerDisabled(); 535 } 536 onMobileDataChanged()537 void onMobileDataChanged() { 538 checkDefaultData(); 539 notifyListenersIfNecessary(); 540 } 541 isDataDisabled()542 boolean isDataDisabled() { 543 return !mPhone.isDataConnectionAllowed(); 544 } 545 546 @VisibleForTesting setActivity(int activity)547 void setActivity(int activity) { 548 mCurrentState.activityIn = activity == TelephonyManager.DATA_ACTIVITY_INOUT 549 || activity == TelephonyManager.DATA_ACTIVITY_IN; 550 mCurrentState.activityOut = activity == TelephonyManager.DATA_ACTIVITY_INOUT 551 || activity == TelephonyManager.DATA_ACTIVITY_OUT; 552 notifyListenersIfNecessary(); 553 } 554 recordLastMobileStatus(String mobileStatus)555 private void recordLastMobileStatus(String mobileStatus) { 556 mMobileStatusHistory[mMobileStatusHistoryIndex] = mobileStatus; 557 mMobileStatusHistoryIndex = (mMobileStatusHistoryIndex + 1) % STATUS_HISTORY_SIZE; 558 } 559 560 @Override dump(PrintWriter pw)561 public void dump(PrintWriter pw) { 562 super.dump(pw); 563 pw.println(" mSubscription=" + mSubscriptionInfo + ","); 564 pw.println(" mInflateSignalStrengths=" + mInflateSignalStrengths + ","); 565 pw.println(" isDataDisabled=" + isDataDisabled() + ","); 566 pw.println(" mNetworkToIconLookup=" + mNetworkToIconLookup + ","); 567 pw.println(" mMobileStatusTracker.isListening=" + mMobileStatusTracker.isListening()); 568 pw.println(" MobileStatusHistory"); 569 int size = 0; 570 for (int i = 0; i < STATUS_HISTORY_SIZE; i++) { 571 if (mMobileStatusHistory[i] != null) { 572 size++; 573 } 574 } 575 // Print out the previous states in ordered number. 576 for (int i = mMobileStatusHistoryIndex + STATUS_HISTORY_SIZE - 1; 577 i >= mMobileStatusHistoryIndex + STATUS_HISTORY_SIZE - size; i--) { 578 pw.println(" Previous MobileStatus(" 579 + (mMobileStatusHistoryIndex + STATUS_HISTORY_SIZE - i) + "): " 580 + mMobileStatusHistory[i & (STATUS_HISTORY_SIZE - 1)]); 581 } 582 583 dumpTableData(pw); 584 } 585 586 /** Box for QS icon info */ 587 private static final class QsInfo { 588 final int ratTypeIcon; 589 final IconState icon; 590 final CharSequence description; 591 QsInfo(int typeIcon, IconState iconState, CharSequence desc)592 QsInfo(int typeIcon, IconState iconState, CharSequence desc) { 593 ratTypeIcon = typeIcon; 594 icon = iconState; 595 description = desc; 596 } 597 598 @Override toString()599 public String toString() { 600 return "QsInfo: ratTypeIcon=" + ratTypeIcon + " icon=" + icon; 601 } 602 } 603 604 /** Box for status bar icon info */ 605 private static final class SbInfo { 606 final boolean showTriangle; 607 final int ratTypeIcon; 608 final IconState icon; 609 SbInfo(boolean show, int typeIcon, IconState iconState)610 SbInfo(boolean show, int typeIcon, IconState iconState) { 611 showTriangle = show; 612 ratTypeIcon = typeIcon; 613 icon = iconState; 614 } 615 616 @Override toString()617 public String toString() { 618 return "SbInfo: showTriangle=" + showTriangle + " ratTypeIcon=" + ratTypeIcon 619 + " icon=" + icon; 620 } 621 } 622 } 623