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