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.policy; 17 18 import android.content.Context; 19 import android.content.Intent; 20 import android.database.ContentObserver; 21 import android.net.NetworkCapabilities; 22 import android.os.Handler; 23 import android.os.Looper; 24 import android.provider.Settings.Global; 25 import android.telephony.PhoneStateListener; 26 import android.telephony.ServiceState; 27 import android.telephony.SignalStrength; 28 import android.telephony.SubscriptionInfo; 29 import android.telephony.SubscriptionManager; 30 import android.telephony.TelephonyManager; 31 import android.text.TextUtils; 32 import android.util.Log; 33 import android.util.SparseArray; 34 35 import com.android.internal.annotations.VisibleForTesting; 36 import com.android.internal.telephony.TelephonyIntents; 37 import com.android.internal.telephony.cdma.EriInfo; 38 import com.android.systemui.R; 39 import com.android.systemui.statusbar.phone.SignalDrawable; 40 import com.android.systemui.statusbar.policy.NetworkController.IconState; 41 import com.android.systemui.statusbar.policy.NetworkController.SignalCallback; 42 import com.android.systemui.statusbar.policy.NetworkControllerImpl.Config; 43 import com.android.systemui.statusbar.policy.NetworkControllerImpl.SubscriptionDefaults; 44 45 import java.io.PrintWriter; 46 import java.util.BitSet; 47 import java.util.Objects; 48 49 50 public class MobileSignalController extends SignalController< 51 MobileSignalController.MobileState, MobileSignalController.MobileIconGroup> { 52 private final TelephonyManager mPhone; 53 private final SubscriptionDefaults mDefaults; 54 private final String mNetworkNameDefault; 55 private final String mNetworkNameSeparator; 56 private final ContentObserver mObserver; 57 @VisibleForTesting 58 final PhoneStateListener mPhoneStateListener; 59 // Save entire info for logging, we only use the id. 60 final SubscriptionInfo mSubscriptionInfo; 61 62 // @VisibleForDemoMode 63 final SparseArray<MobileIconGroup> mNetworkToIconLookup; 64 65 // Since some pieces of the phone state are interdependent we store it locally, 66 // this could potentially become part of MobileState for simplification/complication 67 // of code. 68 private int mDataNetType = TelephonyManager.NETWORK_TYPE_UNKNOWN; 69 private int mDataState = TelephonyManager.DATA_DISCONNECTED; 70 private ServiceState mServiceState; 71 private SignalStrength mSignalStrength; 72 private MobileIconGroup mDefaultIcons; 73 private Config mConfig; 74 75 // TODO: Reduce number of vars passed in, if we have the NetworkController, probably don't 76 // need listener lists anymore. 77 public MobileSignalController(Context context, Config config, boolean hasMobileData, 78 TelephonyManager phone, CallbackHandler callbackHandler, 79 NetworkControllerImpl networkController, SubscriptionInfo info, 80 SubscriptionDefaults defaults, Looper receiverLooper) { 81 super("MobileSignalController(" + info.getSubscriptionId() + ")", context, 82 NetworkCapabilities.TRANSPORT_CELLULAR, callbackHandler, 83 networkController); 84 mNetworkToIconLookup = new SparseArray<>(); 85 mConfig = config; 86 mPhone = phone; 87 mDefaults = defaults; 88 mSubscriptionInfo = info; 89 mPhoneStateListener = new MobilePhoneStateListener(info.getSubscriptionId(), 90 receiverLooper); 91 mNetworkNameSeparator = getStringIfExists(R.string.status_bar_network_name_separator); 92 mNetworkNameDefault = getStringIfExists( 93 com.android.internal.R.string.lockscreen_carrier_default); 94 95 mapIconSets(); 96 97 String networkName = info.getCarrierName() != null ? info.getCarrierName().toString() 98 : mNetworkNameDefault; 99 mLastState.networkName = mCurrentState.networkName = networkName; 100 mLastState.networkNameData = mCurrentState.networkNameData = networkName; 101 mLastState.enabled = mCurrentState.enabled = hasMobileData; 102 mLastState.iconGroup = mCurrentState.iconGroup = mDefaultIcons; 103 // Get initial data sim state. 104 updateDataSim(); 105 mObserver = new ContentObserver(new Handler(receiverLooper)) { 106 @Override 107 public void onChange(boolean selfChange) { 108 updateTelephony(); 109 } 110 }; 111 } 112 113 public void setConfiguration(Config config) { 114 mConfig = config; 115 mapIconSets(); 116 updateTelephony(); 117 } 118 119 public int getDataContentDescription() { 120 return getIcons().mDataContentDescription; 121 } 122 123 public void setAirplaneMode(boolean airplaneMode) { 124 mCurrentState.airplaneMode = airplaneMode; 125 notifyListenersIfNecessary(); 126 } 127 128 public void setUserSetupComplete(boolean userSetup) { 129 mCurrentState.userSetup = userSetup; 130 notifyListenersIfNecessary(); 131 } 132 133 @Override 134 public void updateConnectivity(BitSet connectedTransports, BitSet validatedTransports) { 135 boolean isValidated = validatedTransports.get(mTransportType); 136 mCurrentState.isDefault = connectedTransports.get(mTransportType); 137 // Only show this as not having connectivity if we are default. 138 mCurrentState.inetCondition = (isValidated || !mCurrentState.isDefault) ? 1 : 0; 139 notifyListenersIfNecessary(); 140 } 141 142 public void setCarrierNetworkChangeMode(boolean carrierNetworkChangeMode) { 143 mCurrentState.carrierNetworkChangeMode = carrierNetworkChangeMode; 144 updateTelephony(); 145 } 146 147 /** 148 * Start listening for phone state changes. 149 */ 150 public void registerListener() { 151 mPhone.listen(mPhoneStateListener, 152 PhoneStateListener.LISTEN_SERVICE_STATE 153 | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS 154 | PhoneStateListener.LISTEN_CALL_STATE 155 | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE 156 | PhoneStateListener.LISTEN_DATA_ACTIVITY 157 | PhoneStateListener.LISTEN_CARRIER_NETWORK_CHANGE); 158 mContext.getContentResolver().registerContentObserver(Global.getUriFor(Global.MOBILE_DATA), 159 true, mObserver); 160 mContext.getContentResolver().registerContentObserver(Global.getUriFor( 161 Global.MOBILE_DATA + mSubscriptionInfo.getSubscriptionId()), 162 true, mObserver); 163 } 164 165 /** 166 * Stop listening for phone state changes. 167 */ 168 public void unregisterListener() { 169 mPhone.listen(mPhoneStateListener, 0); 170 mContext.getContentResolver().unregisterContentObserver(mObserver); 171 } 172 173 /** 174 * Produce a mapping of data network types to icon groups for simple and quick use in 175 * updateTelephony. 176 */ 177 private void mapIconSets() { 178 mNetworkToIconLookup.clear(); 179 180 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EVDO_0, TelephonyIcons.THREE_G); 181 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EVDO_A, TelephonyIcons.THREE_G); 182 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EVDO_B, TelephonyIcons.THREE_G); 183 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EHRPD, TelephonyIcons.THREE_G); 184 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_UMTS, TelephonyIcons.THREE_G); 185 186 if (!mConfig.showAtLeast3G) { 187 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_UNKNOWN, 188 TelephonyIcons.UNKNOWN); 189 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EDGE, TelephonyIcons.E); 190 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_CDMA, TelephonyIcons.ONE_X); 191 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_1xRTT, TelephonyIcons.ONE_X); 192 193 mDefaultIcons = TelephonyIcons.G; 194 } else { 195 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_UNKNOWN, 196 TelephonyIcons.THREE_G); 197 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_EDGE, 198 TelephonyIcons.THREE_G); 199 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_CDMA, 200 TelephonyIcons.THREE_G); 201 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_1xRTT, 202 TelephonyIcons.THREE_G); 203 mDefaultIcons = TelephonyIcons.THREE_G; 204 } 205 206 MobileIconGroup hGroup = TelephonyIcons.THREE_G; 207 if (mConfig.hspaDataDistinguishable) { 208 hGroup = TelephonyIcons.H; 209 } 210 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSDPA, hGroup); 211 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSUPA, hGroup); 212 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSPA, hGroup); 213 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_HSPAP, hGroup); 214 215 if (mConfig.show4gForLte) { 216 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE, TelephonyIcons.FOUR_G); 217 if (mConfig.hideLtePlus) { 218 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE_CA, 219 TelephonyIcons.FOUR_G); 220 } else { 221 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE_CA, 222 TelephonyIcons.FOUR_G_PLUS); 223 } 224 } else { 225 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE, TelephonyIcons.LTE); 226 if (mConfig.hideLtePlus) { 227 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE_CA, 228 TelephonyIcons.LTE); 229 } else { 230 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_LTE_CA, 231 TelephonyIcons.LTE_PLUS); 232 } 233 } 234 mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_IWLAN, TelephonyIcons.WFC); 235 } 236 237 private int getNumLevels() { 238 return SignalStrength.NUM_SIGNAL_STRENGTH_BINS; 239 } 240 241 @Override 242 public int getCurrentIconId() { 243 if (mCurrentState.iconGroup == TelephonyIcons.CARRIER_NETWORK_CHANGE) { 244 return SignalDrawable.getCarrierChangeState(getNumLevels()); 245 } else if (mCurrentState.connected) { 246 return SignalDrawable.getState(mCurrentState.level, getNumLevels(), 247 mCurrentState.inetCondition == 0); 248 } else if (mCurrentState.enabled) { 249 return SignalDrawable.getEmptyState(getNumLevels()); 250 } else { 251 return 0; 252 } 253 } 254 255 @Override 256 public int getQsCurrentIconId() { 257 if (mCurrentState.airplaneMode) { 258 return SignalDrawable.getAirplaneModeState(getNumLevels()); 259 } 260 261 return getCurrentIconId(); 262 } 263 264 @Override 265 public void notifyListeners(SignalCallback callback) { 266 MobileIconGroup icons = getIcons(); 267 268 String contentDescription = getStringIfExists(getContentDescription()); 269 String dataContentDescription = getStringIfExists(icons.mDataContentDescription); 270 final boolean dataDisabled = mCurrentState.iconGroup == TelephonyIcons.DATA_DISABLED 271 && mCurrentState.userSetup; 272 273 // Show icon in QS when we are connected or data is disabled. 274 boolean showDataIcon = mCurrentState.dataConnected || dataDisabled; 275 IconState statusIcon = new IconState(mCurrentState.enabled && !mCurrentState.airplaneMode, 276 getCurrentIconId(), contentDescription); 277 278 int qsTypeIcon = 0; 279 IconState qsIcon = null; 280 String description = null; 281 // Only send data sim callbacks to QS. 282 if (mCurrentState.dataSim) { 283 qsTypeIcon = showDataIcon ? icons.mQsDataType : 0; 284 qsIcon = new IconState(mCurrentState.enabled 285 && !mCurrentState.isEmergency, getQsCurrentIconId(), contentDescription); 286 description = mCurrentState.isEmergency ? null : mCurrentState.networkName; 287 } 288 boolean activityIn = mCurrentState.dataConnected 289 && !mCurrentState.carrierNetworkChangeMode 290 && mCurrentState.activityIn; 291 boolean activityOut = mCurrentState.dataConnected 292 && !mCurrentState.carrierNetworkChangeMode 293 && mCurrentState.activityOut; 294 showDataIcon &= mCurrentState.isDefault || dataDisabled; 295 int typeIcon = showDataIcon ? icons.mDataType : 0; 296 callback.setMobileDataIndicators(statusIcon, qsIcon, typeIcon, qsTypeIcon, 297 activityIn, activityOut, dataContentDescription, description, icons.mIsWide, 298 mSubscriptionInfo.getSubscriptionId(), mCurrentState.roaming); 299 } 300 301 @Override 302 protected MobileState cleanState() { 303 return new MobileState(); 304 } 305 306 private boolean hasService() { 307 if (mServiceState != null) { 308 // Consider the device to be in service if either voice or data 309 // service is available. Some SIM cards are marketed as data-only 310 // and do not support voice service, and on these SIM cards, we 311 // want to show signal bars for data service as well as the "no 312 // service" or "emergency calls only" text that indicates that voice 313 // is not available. 314 switch (mServiceState.getVoiceRegState()) { 315 case ServiceState.STATE_POWER_OFF: 316 return false; 317 case ServiceState.STATE_OUT_OF_SERVICE: 318 case ServiceState.STATE_EMERGENCY_ONLY: 319 return mServiceState.getDataRegState() == ServiceState.STATE_IN_SERVICE; 320 default: 321 return true; 322 } 323 } else { 324 return false; 325 } 326 } 327 328 private boolean isCdma() { 329 return (mSignalStrength != null) && !mSignalStrength.isGsm(); 330 } 331 332 public boolean isEmergencyOnly() { 333 return (mServiceState != null && mServiceState.isEmergencyOnly()); 334 } 335 336 private boolean isRoaming() { 337 // During a carrier change, roaming indications need to be supressed. 338 if (isCarrierNetworkChangeActive()) { 339 return false; 340 } 341 if (isCdma()) { 342 final int iconMode = mServiceState.getCdmaEriIconMode(); 343 return mServiceState.getCdmaEriIconIndex() != EriInfo.ROAMING_INDICATOR_OFF 344 && (iconMode == EriInfo.ROAMING_ICON_MODE_NORMAL 345 || iconMode == EriInfo.ROAMING_ICON_MODE_FLASH); 346 } else { 347 return mServiceState != null && mServiceState.getRoaming(); 348 } 349 } 350 351 private boolean isCarrierNetworkChangeActive() { 352 return mCurrentState.carrierNetworkChangeMode; 353 } 354 355 public void handleBroadcast(Intent intent) { 356 String action = intent.getAction(); 357 if (action.equals(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION)) { 358 updateNetworkName(intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_SPN, false), 359 intent.getStringExtra(TelephonyIntents.EXTRA_SPN), 360 intent.getStringExtra(TelephonyIntents.EXTRA_DATA_SPN), 361 intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_PLMN, false), 362 intent.getStringExtra(TelephonyIntents.EXTRA_PLMN)); 363 notifyListenersIfNecessary(); 364 } else if (action.equals(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)) { 365 updateDataSim(); 366 notifyListenersIfNecessary(); 367 } 368 } 369 370 private void updateDataSim() { 371 int defaultDataSub = mDefaults.getDefaultDataSubId(); 372 if (SubscriptionManager.isValidSubscriptionId(defaultDataSub)) { 373 mCurrentState.dataSim = defaultDataSub == mSubscriptionInfo.getSubscriptionId(); 374 } else { 375 // There doesn't seem to be a data sim selected, however if 376 // there isn't a MobileSignalController with dataSim set, then 377 // QS won't get any callbacks and will be blank. Instead 378 // lets just assume we are the data sim (which will basically 379 // show one at random) in QS until one is selected. The user 380 // should pick one soon after, so we shouldn't be in this state 381 // for long. 382 mCurrentState.dataSim = true; 383 } 384 } 385 386 /** 387 * Updates the network's name based on incoming spn and plmn. 388 */ 389 void updateNetworkName(boolean showSpn, String spn, String dataSpn, 390 boolean showPlmn, String plmn) { 391 if (CHATTY) { 392 Log.d("CarrierLabel", "updateNetworkName showSpn=" + showSpn 393 + " spn=" + spn + " dataSpn=" + dataSpn 394 + " showPlmn=" + showPlmn + " plmn=" + plmn); 395 } 396 StringBuilder str = new StringBuilder(); 397 StringBuilder strData = new StringBuilder(); 398 if (showPlmn && plmn != null) { 399 str.append(plmn); 400 strData.append(plmn); 401 } 402 if (showSpn && spn != null) { 403 if (str.length() != 0) { 404 str.append(mNetworkNameSeparator); 405 } 406 str.append(spn); 407 } 408 if (str.length() != 0) { 409 mCurrentState.networkName = str.toString(); 410 } else { 411 mCurrentState.networkName = mNetworkNameDefault; 412 } 413 if (showSpn && dataSpn != null) { 414 if (strData.length() != 0) { 415 strData.append(mNetworkNameSeparator); 416 } 417 strData.append(dataSpn); 418 } 419 if (strData.length() != 0) { 420 mCurrentState.networkNameData = strData.toString(); 421 } else { 422 mCurrentState.networkNameData = mNetworkNameDefault; 423 } 424 } 425 426 /** 427 * Updates the current state based on mServiceState, mSignalStrength, mDataNetType, 428 * mDataState, and mSimState. It should be called any time one of these is updated. 429 * This will call listeners if necessary. 430 */ 431 private final void updateTelephony() { 432 if (DEBUG) { 433 Log.d(mTag, "updateTelephonySignalStrength: hasService=" + hasService() 434 + " ss=" + mSignalStrength); 435 } 436 mCurrentState.connected = hasService() && mSignalStrength != null; 437 if (mCurrentState.connected) { 438 if (!mSignalStrength.isGsm() && mConfig.alwaysShowCdmaRssi) { 439 mCurrentState.level = mSignalStrength.getCdmaLevel(); 440 } else { 441 mCurrentState.level = mSignalStrength.getLevel(); 442 } 443 } 444 if (mNetworkToIconLookup.indexOfKey(mDataNetType) >= 0) { 445 mCurrentState.iconGroup = mNetworkToIconLookup.get(mDataNetType); 446 } else { 447 mCurrentState.iconGroup = mDefaultIcons; 448 } 449 mCurrentState.dataConnected = mCurrentState.connected 450 && mDataState == TelephonyManager.DATA_CONNECTED; 451 452 mCurrentState.roaming = isRoaming(); 453 if (isCarrierNetworkChangeActive()) { 454 mCurrentState.iconGroup = TelephonyIcons.CARRIER_NETWORK_CHANGE; 455 } else if (isDataDisabled()) { 456 mCurrentState.iconGroup = TelephonyIcons.DATA_DISABLED; 457 } 458 if (isEmergencyOnly() != mCurrentState.isEmergency) { 459 mCurrentState.isEmergency = isEmergencyOnly(); 460 mNetworkController.recalculateEmergency(); 461 } 462 // Fill in the network name if we think we have it. 463 if (mCurrentState.networkName == mNetworkNameDefault && mServiceState != null 464 && !TextUtils.isEmpty(mServiceState.getOperatorAlphaShort())) { 465 mCurrentState.networkName = mServiceState.getOperatorAlphaShort(); 466 } 467 468 notifyListenersIfNecessary(); 469 } 470 471 private boolean isDataDisabled() { 472 return !mPhone.getDataEnabled(mSubscriptionInfo.getSubscriptionId()); 473 } 474 475 @VisibleForTesting 476 void setActivity(int activity) { 477 mCurrentState.activityIn = activity == TelephonyManager.DATA_ACTIVITY_INOUT 478 || activity == TelephonyManager.DATA_ACTIVITY_IN; 479 mCurrentState.activityOut = activity == TelephonyManager.DATA_ACTIVITY_INOUT 480 || activity == TelephonyManager.DATA_ACTIVITY_OUT; 481 notifyListenersIfNecessary(); 482 } 483 484 @Override 485 public void dump(PrintWriter pw) { 486 super.dump(pw); 487 pw.println(" mSubscription=" + mSubscriptionInfo + ","); 488 pw.println(" mServiceState=" + mServiceState + ","); 489 pw.println(" mSignalStrength=" + mSignalStrength + ","); 490 pw.println(" mDataState=" + mDataState + ","); 491 pw.println(" mDataNetType=" + mDataNetType + ","); 492 } 493 494 class MobilePhoneStateListener extends PhoneStateListener { 495 public MobilePhoneStateListener(int subId, Looper looper) { 496 super(subId, looper); 497 } 498 499 @Override 500 public void onSignalStrengthsChanged(SignalStrength signalStrength) { 501 if (DEBUG) { 502 Log.d(mTag, "onSignalStrengthsChanged signalStrength=" + signalStrength + 503 ((signalStrength == null) ? "" : (" level=" + signalStrength.getLevel()))); 504 } 505 mSignalStrength = signalStrength; 506 updateTelephony(); 507 } 508 509 @Override 510 public void onServiceStateChanged(ServiceState state) { 511 if (DEBUG) { 512 Log.d(mTag, "onServiceStateChanged voiceState=" + state.getVoiceRegState() 513 + " dataState=" + state.getDataRegState()); 514 } 515 mServiceState = state; 516 mDataNetType = state.getDataNetworkType(); 517 if (mDataNetType == TelephonyManager.NETWORK_TYPE_LTE && mServiceState != null && 518 mServiceState.isUsingCarrierAggregation()) { 519 mDataNetType = TelephonyManager.NETWORK_TYPE_LTE_CA; 520 } 521 updateTelephony(); 522 } 523 524 @Override 525 public void onDataConnectionStateChanged(int state, int networkType) { 526 if (DEBUG) { 527 Log.d(mTag, "onDataConnectionStateChanged: state=" + state 528 + " type=" + networkType); 529 } 530 mDataState = state; 531 mDataNetType = networkType; 532 if (mDataNetType == TelephonyManager.NETWORK_TYPE_LTE && mServiceState != null && 533 mServiceState.isUsingCarrierAggregation()) { 534 mDataNetType = TelephonyManager.NETWORK_TYPE_LTE_CA; 535 } 536 updateTelephony(); 537 } 538 539 @Override 540 public void onDataActivity(int direction) { 541 if (DEBUG) { 542 Log.d(mTag, "onDataActivity: direction=" + direction); 543 } 544 setActivity(direction); 545 } 546 547 @Override 548 public void onCarrierNetworkChange(boolean active) { 549 if (DEBUG) { 550 Log.d(mTag, "onCarrierNetworkChange: active=" + active); 551 } 552 mCurrentState.carrierNetworkChangeMode = active; 553 554 updateTelephony(); 555 } 556 }; 557 558 static class MobileIconGroup extends SignalController.IconGroup { 559 final int mDataContentDescription; // mContentDescriptionDataType 560 final int mDataType; 561 final boolean mIsWide; 562 final int mQsDataType; 563 564 public MobileIconGroup(String name, int[][] sbIcons, int[][] qsIcons, int[] contentDesc, 565 int sbNullState, int qsNullState, int sbDiscState, int qsDiscState, 566 int discContentDesc, int dataContentDesc, int dataType, boolean isWide, 567 int qsDataType) { 568 super(name, sbIcons, qsIcons, contentDesc, sbNullState, qsNullState, sbDiscState, 569 qsDiscState, discContentDesc); 570 mDataContentDescription = dataContentDesc; 571 mDataType = dataType; 572 mIsWide = isWide; 573 mQsDataType = qsDataType; 574 } 575 } 576 577 static class MobileState extends SignalController.State { 578 String networkName; 579 String networkNameData; 580 boolean dataSim; 581 boolean dataConnected; 582 boolean isEmergency; 583 boolean airplaneMode; 584 boolean carrierNetworkChangeMode; 585 boolean isDefault; 586 boolean userSetup; 587 boolean roaming; 588 589 @Override 590 public void copyFrom(State s) { 591 super.copyFrom(s); 592 MobileState state = (MobileState) s; 593 dataSim = state.dataSim; 594 networkName = state.networkName; 595 networkNameData = state.networkNameData; 596 dataConnected = state.dataConnected; 597 isDefault = state.isDefault; 598 isEmergency = state.isEmergency; 599 airplaneMode = state.airplaneMode; 600 carrierNetworkChangeMode = state.carrierNetworkChangeMode; 601 userSetup = state.userSetup; 602 roaming = state.roaming; 603 } 604 605 @Override 606 protected void toString(StringBuilder builder) { 607 super.toString(builder); 608 builder.append(','); 609 builder.append("dataSim=").append(dataSim).append(','); 610 builder.append("networkName=").append(networkName).append(','); 611 builder.append("networkNameData=").append(networkNameData).append(','); 612 builder.append("dataConnected=").append(dataConnected).append(','); 613 builder.append("roaming=").append(roaming).append(','); 614 builder.append("isDefault=").append(isDefault).append(','); 615 builder.append("isEmergency=").append(isEmergency).append(','); 616 builder.append("airplaneMode=").append(airplaneMode).append(','); 617 builder.append("carrierNetworkChangeMode=").append(carrierNetworkChangeMode) 618 .append(','); 619 builder.append("userSetup=").append(userSetup); 620 } 621 622 @Override 623 public boolean equals(Object o) { 624 return super.equals(o) 625 && Objects.equals(((MobileState) o).networkName, networkName) 626 && Objects.equals(((MobileState) o).networkNameData, networkNameData) 627 && ((MobileState) o).dataSim == dataSim 628 && ((MobileState) o).dataConnected == dataConnected 629 && ((MobileState) o).isEmergency == isEmergency 630 && ((MobileState) o).airplaneMode == airplaneMode 631 && ((MobileState) o).carrierNetworkChangeMode == carrierNetworkChangeMode 632 && ((MobileState) o).userSetup == userSetup 633 && ((MobileState) o).isDefault == isDefault 634 && ((MobileState) o).roaming == roaming; 635 } 636 } 637 } 638