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 if (mConfig.inflateSignalStrengths) { 239 return SignalStrength.NUM_SIGNAL_STRENGTH_BINS + 1; 240 } 241 return SignalStrength.NUM_SIGNAL_STRENGTH_BINS; 242 } 243 244 @Override 245 public int getCurrentIconId() { 246 if (mCurrentState.iconGroup == TelephonyIcons.CARRIER_NETWORK_CHANGE) { 247 return SignalDrawable.getCarrierChangeState(getNumLevels()); 248 } else if (mCurrentState.connected) { 249 int level = mCurrentState.level; 250 if (mConfig.inflateSignalStrengths) { 251 level++; 252 } 253 return SignalDrawable.getState(level, getNumLevels(), 254 mCurrentState.inetCondition == 0); 255 } else if (mCurrentState.enabled) { 256 return SignalDrawable.getEmptyState(getNumLevels()); 257 } else { 258 return 0; 259 } 260 } 261 262 @Override 263 public int getQsCurrentIconId() { 264 if (mCurrentState.airplaneMode) { 265 return SignalDrawable.getAirplaneModeState(getNumLevels()); 266 } 267 268 return getCurrentIconId(); 269 } 270 271 @Override 272 public void notifyListeners(SignalCallback callback) { 273 MobileIconGroup icons = getIcons(); 274 275 String contentDescription = getStringIfExists(getContentDescription()); 276 String dataContentDescription = getStringIfExists(icons.mDataContentDescription); 277 final boolean dataDisabled = mCurrentState.iconGroup == TelephonyIcons.DATA_DISABLED 278 && mCurrentState.userSetup; 279 280 // Show icon in QS when we are connected or data is disabled. 281 boolean showDataIcon = mCurrentState.dataConnected || dataDisabled; 282 IconState statusIcon = new IconState(mCurrentState.enabled && !mCurrentState.airplaneMode, 283 getCurrentIconId(), contentDescription); 284 285 int qsTypeIcon = 0; 286 IconState qsIcon = null; 287 String description = null; 288 // Only send data sim callbacks to QS. 289 if (mCurrentState.dataSim) { 290 qsTypeIcon = showDataIcon ? icons.mQsDataType : 0; 291 qsIcon = new IconState(mCurrentState.enabled 292 && !mCurrentState.isEmergency, getQsCurrentIconId(), contentDescription); 293 description = mCurrentState.isEmergency ? null : mCurrentState.networkName; 294 } 295 boolean activityIn = mCurrentState.dataConnected 296 && !mCurrentState.carrierNetworkChangeMode 297 && mCurrentState.activityIn; 298 boolean activityOut = mCurrentState.dataConnected 299 && !mCurrentState.carrierNetworkChangeMode 300 && mCurrentState.activityOut; 301 showDataIcon &= mCurrentState.isDefault || dataDisabled; 302 int typeIcon = showDataIcon ? icons.mDataType : 0; 303 callback.setMobileDataIndicators(statusIcon, qsIcon, typeIcon, qsTypeIcon, 304 activityIn, activityOut, dataContentDescription, description, icons.mIsWide, 305 mSubscriptionInfo.getSubscriptionId(), mCurrentState.roaming); 306 } 307 308 @Override 309 protected MobileState cleanState() { 310 return new MobileState(); 311 } 312 313 private boolean hasService() { 314 if (mServiceState != null) { 315 // Consider the device to be in service if either voice or data 316 // service is available. Some SIM cards are marketed as data-only 317 // and do not support voice service, and on these SIM cards, we 318 // want to show signal bars for data service as well as the "no 319 // service" or "emergency calls only" text that indicates that voice 320 // is not available. 321 switch (mServiceState.getVoiceRegState()) { 322 case ServiceState.STATE_POWER_OFF: 323 return false; 324 case ServiceState.STATE_OUT_OF_SERVICE: 325 case ServiceState.STATE_EMERGENCY_ONLY: 326 return mServiceState.getDataRegState() == ServiceState.STATE_IN_SERVICE; 327 default: 328 return true; 329 } 330 } else { 331 return false; 332 } 333 } 334 335 private boolean isCdma() { 336 return (mSignalStrength != null) && !mSignalStrength.isGsm(); 337 } 338 339 public boolean isEmergencyOnly() { 340 return (mServiceState != null && mServiceState.isEmergencyOnly()); 341 } 342 343 private boolean isRoaming() { 344 // During a carrier change, roaming indications need to be supressed. 345 if (isCarrierNetworkChangeActive()) { 346 return false; 347 } 348 if (isCdma() && mServiceState != null) { 349 final int iconMode = mServiceState.getCdmaEriIconMode(); 350 return mServiceState.getCdmaEriIconIndex() != EriInfo.ROAMING_INDICATOR_OFF 351 && (iconMode == EriInfo.ROAMING_ICON_MODE_NORMAL 352 || iconMode == EriInfo.ROAMING_ICON_MODE_FLASH); 353 } else { 354 return mServiceState != null && mServiceState.getRoaming(); 355 } 356 } 357 358 private boolean isCarrierNetworkChangeActive() { 359 return mCurrentState.carrierNetworkChangeMode; 360 } 361 362 public void handleBroadcast(Intent intent) { 363 String action = intent.getAction(); 364 if (action.equals(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION)) { 365 updateNetworkName(intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_SPN, false), 366 intent.getStringExtra(TelephonyIntents.EXTRA_SPN), 367 intent.getStringExtra(TelephonyIntents.EXTRA_DATA_SPN), 368 intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_PLMN, false), 369 intent.getStringExtra(TelephonyIntents.EXTRA_PLMN)); 370 notifyListenersIfNecessary(); 371 } else if (action.equals(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)) { 372 updateDataSim(); 373 notifyListenersIfNecessary(); 374 } 375 } 376 377 private void updateDataSim() { 378 int defaultDataSub = mDefaults.getDefaultDataSubId(); 379 if (SubscriptionManager.isValidSubscriptionId(defaultDataSub)) { 380 mCurrentState.dataSim = defaultDataSub == mSubscriptionInfo.getSubscriptionId(); 381 } else { 382 // There doesn't seem to be a data sim selected, however if 383 // there isn't a MobileSignalController with dataSim set, then 384 // QS won't get any callbacks and will be blank. Instead 385 // lets just assume we are the data sim (which will basically 386 // show one at random) in QS until one is selected. The user 387 // should pick one soon after, so we shouldn't be in this state 388 // for long. 389 mCurrentState.dataSim = true; 390 } 391 } 392 393 /** 394 * Updates the network's name based on incoming spn and plmn. 395 */ 396 void updateNetworkName(boolean showSpn, String spn, String dataSpn, 397 boolean showPlmn, String plmn) { 398 if (CHATTY) { 399 Log.d("CarrierLabel", "updateNetworkName showSpn=" + showSpn 400 + " spn=" + spn + " dataSpn=" + dataSpn 401 + " showPlmn=" + showPlmn + " plmn=" + plmn); 402 } 403 StringBuilder str = new StringBuilder(); 404 StringBuilder strData = new StringBuilder(); 405 if (showPlmn && plmn != null) { 406 str.append(plmn); 407 strData.append(plmn); 408 } 409 if (showSpn && spn != null) { 410 if (str.length() != 0) { 411 str.append(mNetworkNameSeparator); 412 } 413 str.append(spn); 414 } 415 if (str.length() != 0) { 416 mCurrentState.networkName = str.toString(); 417 } else { 418 mCurrentState.networkName = mNetworkNameDefault; 419 } 420 if (showSpn && dataSpn != null) { 421 if (strData.length() != 0) { 422 strData.append(mNetworkNameSeparator); 423 } 424 strData.append(dataSpn); 425 } 426 if (strData.length() != 0) { 427 mCurrentState.networkNameData = strData.toString(); 428 } else { 429 mCurrentState.networkNameData = mNetworkNameDefault; 430 } 431 } 432 433 /** 434 * Updates the current state based on mServiceState, mSignalStrength, mDataNetType, 435 * mDataState, and mSimState. It should be called any time one of these is updated. 436 * This will call listeners if necessary. 437 */ 438 private final void updateTelephony() { 439 if (DEBUG) { 440 Log.d(mTag, "updateTelephonySignalStrength: hasService=" + hasService() 441 + " ss=" + mSignalStrength); 442 } 443 mCurrentState.connected = hasService() && mSignalStrength != null; 444 if (mCurrentState.connected) { 445 if (!mSignalStrength.isGsm() && mConfig.alwaysShowCdmaRssi) { 446 mCurrentState.level = mSignalStrength.getCdmaLevel(); 447 } else { 448 mCurrentState.level = mSignalStrength.getLevel(); 449 } 450 } 451 if (mNetworkToIconLookup.indexOfKey(mDataNetType) >= 0) { 452 mCurrentState.iconGroup = mNetworkToIconLookup.get(mDataNetType); 453 } else { 454 mCurrentState.iconGroup = mDefaultIcons; 455 } 456 mCurrentState.dataConnected = mCurrentState.connected 457 && mDataState == TelephonyManager.DATA_CONNECTED; 458 459 mCurrentState.roaming = isRoaming(); 460 if (isCarrierNetworkChangeActive()) { 461 mCurrentState.iconGroup = TelephonyIcons.CARRIER_NETWORK_CHANGE; 462 } else if (isDataDisabled()) { 463 mCurrentState.iconGroup = TelephonyIcons.DATA_DISABLED; 464 } 465 if (isEmergencyOnly() != mCurrentState.isEmergency) { 466 mCurrentState.isEmergency = isEmergencyOnly(); 467 mNetworkController.recalculateEmergency(); 468 } 469 // Fill in the network name if we think we have it. 470 if (mCurrentState.networkName == mNetworkNameDefault && mServiceState != null 471 && !TextUtils.isEmpty(mServiceState.getOperatorAlphaShort())) { 472 mCurrentState.networkName = mServiceState.getOperatorAlphaShort(); 473 } 474 475 notifyListenersIfNecessary(); 476 } 477 478 private boolean isDataDisabled() { 479 return !mPhone.getDataEnabled(mSubscriptionInfo.getSubscriptionId()); 480 } 481 482 @VisibleForTesting 483 void setActivity(int activity) { 484 mCurrentState.activityIn = activity == TelephonyManager.DATA_ACTIVITY_INOUT 485 || activity == TelephonyManager.DATA_ACTIVITY_IN; 486 mCurrentState.activityOut = activity == TelephonyManager.DATA_ACTIVITY_INOUT 487 || activity == TelephonyManager.DATA_ACTIVITY_OUT; 488 notifyListenersIfNecessary(); 489 } 490 491 @Override 492 public void dump(PrintWriter pw) { 493 super.dump(pw); 494 pw.println(" mSubscription=" + mSubscriptionInfo + ","); 495 pw.println(" mServiceState=" + mServiceState + ","); 496 pw.println(" mSignalStrength=" + mSignalStrength + ","); 497 pw.println(" mDataState=" + mDataState + ","); 498 pw.println(" mDataNetType=" + mDataNetType + ","); 499 } 500 501 class MobilePhoneStateListener extends PhoneStateListener { 502 public MobilePhoneStateListener(int subId, Looper looper) { 503 super(subId, looper); 504 } 505 506 @Override 507 public void onSignalStrengthsChanged(SignalStrength signalStrength) { 508 if (DEBUG) { 509 Log.d(mTag, "onSignalStrengthsChanged signalStrength=" + signalStrength + 510 ((signalStrength == null) ? "" : (" level=" + signalStrength.getLevel()))); 511 } 512 mSignalStrength = signalStrength; 513 updateTelephony(); 514 } 515 516 @Override 517 public void onServiceStateChanged(ServiceState state) { 518 if (DEBUG) { 519 Log.d(mTag, "onServiceStateChanged voiceState=" + state.getVoiceRegState() 520 + " dataState=" + state.getDataRegState()); 521 } 522 mServiceState = state; 523 if (state != null) { 524 mDataNetType = state.getDataNetworkType(); 525 if (mDataNetType == TelephonyManager.NETWORK_TYPE_LTE && mServiceState != null && 526 mServiceState.isUsingCarrierAggregation()) { 527 mDataNetType = TelephonyManager.NETWORK_TYPE_LTE_CA; 528 } 529 } 530 updateTelephony(); 531 } 532 533 @Override 534 public void onDataConnectionStateChanged(int state, int networkType) { 535 if (DEBUG) { 536 Log.d(mTag, "onDataConnectionStateChanged: state=" + state 537 + " type=" + networkType); 538 } 539 mDataState = state; 540 mDataNetType = networkType; 541 if (mDataNetType == TelephonyManager.NETWORK_TYPE_LTE && mServiceState != null && 542 mServiceState.isUsingCarrierAggregation()) { 543 mDataNetType = TelephonyManager.NETWORK_TYPE_LTE_CA; 544 } 545 updateTelephony(); 546 } 547 548 @Override 549 public void onDataActivity(int direction) { 550 if (DEBUG) { 551 Log.d(mTag, "onDataActivity: direction=" + direction); 552 } 553 setActivity(direction); 554 } 555 556 @Override 557 public void onCarrierNetworkChange(boolean active) { 558 if (DEBUG) { 559 Log.d(mTag, "onCarrierNetworkChange: active=" + active); 560 } 561 mCurrentState.carrierNetworkChangeMode = active; 562 563 updateTelephony(); 564 } 565 }; 566 567 static class MobileIconGroup extends SignalController.IconGroup { 568 final int mDataContentDescription; // mContentDescriptionDataType 569 final int mDataType; 570 final boolean mIsWide; 571 final int mQsDataType; 572 573 public MobileIconGroup(String name, int[][] sbIcons, int[][] qsIcons, int[] contentDesc, 574 int sbNullState, int qsNullState, int sbDiscState, int qsDiscState, 575 int discContentDesc, int dataContentDesc, int dataType, boolean isWide, 576 int qsDataType) { 577 super(name, sbIcons, qsIcons, contentDesc, sbNullState, qsNullState, sbDiscState, 578 qsDiscState, discContentDesc); 579 mDataContentDescription = dataContentDesc; 580 mDataType = dataType; 581 mIsWide = isWide; 582 mQsDataType = qsDataType; 583 } 584 } 585 586 static class MobileState extends SignalController.State { 587 String networkName; 588 String networkNameData; 589 boolean dataSim; 590 boolean dataConnected; 591 boolean isEmergency; 592 boolean airplaneMode; 593 boolean carrierNetworkChangeMode; 594 boolean isDefault; 595 boolean userSetup; 596 boolean roaming; 597 598 @Override 599 public void copyFrom(State s) { 600 super.copyFrom(s); 601 MobileState state = (MobileState) s; 602 dataSim = state.dataSim; 603 networkName = state.networkName; 604 networkNameData = state.networkNameData; 605 dataConnected = state.dataConnected; 606 isDefault = state.isDefault; 607 isEmergency = state.isEmergency; 608 airplaneMode = state.airplaneMode; 609 carrierNetworkChangeMode = state.carrierNetworkChangeMode; 610 userSetup = state.userSetup; 611 roaming = state.roaming; 612 } 613 614 @Override 615 protected void toString(StringBuilder builder) { 616 super.toString(builder); 617 builder.append(','); 618 builder.append("dataSim=").append(dataSim).append(','); 619 builder.append("networkName=").append(networkName).append(','); 620 builder.append("networkNameData=").append(networkNameData).append(','); 621 builder.append("dataConnected=").append(dataConnected).append(','); 622 builder.append("roaming=").append(roaming).append(','); 623 builder.append("isDefault=").append(isDefault).append(','); 624 builder.append("isEmergency=").append(isEmergency).append(','); 625 builder.append("airplaneMode=").append(airplaneMode).append(','); 626 builder.append("carrierNetworkChangeMode=").append(carrierNetworkChangeMode) 627 .append(','); 628 builder.append("userSetup=").append(userSetup); 629 } 630 631 @Override 632 public boolean equals(Object o) { 633 return super.equals(o) 634 && Objects.equals(((MobileState) o).networkName, networkName) 635 && Objects.equals(((MobileState) o).networkNameData, networkNameData) 636 && ((MobileState) o).dataSim == dataSim 637 && ((MobileState) o).dataConnected == dataConnected 638 && ((MobileState) o).isEmergency == isEmergency 639 && ((MobileState) o).airplaneMode == airplaneMode 640 && ((MobileState) o).carrierNetworkChangeMode == carrierNetworkChangeMode 641 && ((MobileState) o).userSetup == userSetup 642 && ((MobileState) o).isDefault == isDefault 643 && ((MobileState) o).roaming == roaming; 644 } 645 } 646 } 647