1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.internal.telephony.cdma; 18 19 import android.app.AlarmManager; 20 import android.content.ContentResolver; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.database.ContentObserver; 24 import android.os.AsyncResult; 25 import android.os.Build; 26 import android.os.Handler; 27 import android.os.Message; 28 import android.os.PowerManager; 29 import android.os.Registrant; 30 import android.os.RegistrantList; 31 import android.os.SystemClock; 32 import android.os.SystemProperties; 33 import android.os.UserHandle; 34 import android.provider.Settings; 35 import android.provider.Settings.SettingNotFoundException; 36 import android.telephony.CellInfo; 37 import android.telephony.CellInfoCdma; 38 import android.telephony.Rlog; 39 import android.telephony.ServiceState; 40 import android.telephony.SignalStrength; 41 import android.telephony.cdma.CdmaCellLocation; 42 import android.text.TextUtils; 43 import android.util.EventLog; 44 import android.util.TimeUtils; 45 46 import com.android.internal.telephony.CommandException; 47 import com.android.internal.telephony.CommandsInterface; 48 import com.android.internal.telephony.CommandsInterface.RadioState; 49 import com.android.internal.telephony.EventLogTags; 50 import com.android.internal.telephony.MccTable; 51 import com.android.internal.telephony.Phone; 52 import com.android.internal.telephony.PhoneConstants; 53 import com.android.internal.telephony.ServiceStateTracker; 54 import com.android.internal.telephony.TelephonyIntents; 55 import com.android.internal.telephony.TelephonyProperties; 56 import com.android.internal.telephony.dataconnection.DcTrackerBase; 57 import com.android.internal.telephony.uicc.UiccCardApplication; 58 import com.android.internal.telephony.uicc.UiccController; 59 60 import java.io.FileDescriptor; 61 import java.io.PrintWriter; 62 import java.util.Arrays; 63 import java.util.Calendar; 64 import java.util.Date; 65 import java.util.List; 66 import java.util.TimeZone; 67 68 /** 69 * {@hide} 70 */ 71 public class CdmaServiceStateTracker extends ServiceStateTracker { 72 static final String LOG_TAG = "CdmaSST"; 73 74 CDMAPhone mPhone; 75 CdmaCellLocation mCellLoc; 76 CdmaCellLocation mNewCellLoc; 77 78 // Min values used to by getOtasp() 79 private static final String UNACTIVATED_MIN2_VALUE = "000000"; 80 private static final String UNACTIVATED_MIN_VALUE = "1111110111"; 81 82 // Current Otasp value 83 int mCurrentOtaspMode = OTASP_UNINITIALIZED; 84 85 /** if time between NITZ updates is less than mNitzUpdateSpacing the update may be ignored. */ 86 private static final int NITZ_UPDATE_SPACING_DEFAULT = 1000 * 60 * 10; 87 private int mNitzUpdateSpacing = SystemProperties.getInt("ro.nitz_update_spacing", 88 NITZ_UPDATE_SPACING_DEFAULT); 89 90 /** If mNitzUpdateSpacing hasn't been exceeded but update is > mNitzUpdate do the update */ 91 private static final int NITZ_UPDATE_DIFF_DEFAULT = 2000; 92 private int mNitzUpdateDiff = SystemProperties.getInt("ro.nitz_update_diff", 93 NITZ_UPDATE_DIFF_DEFAULT); 94 95 private boolean mCdmaRoaming = false; 96 private int mRoamingIndicator; 97 private boolean mIsInPrl; 98 private int mDefaultRoamingIndicator; 99 100 /** 101 * Initially assume no data connection. 102 */ 103 protected int mRegistrationState = -1; 104 protected RegistrantList mCdmaForSubscriptionInfoReadyRegistrants = new RegistrantList(); 105 106 /** 107 * Sometimes we get the NITZ time before we know what country we 108 * are in. Keep the time zone information from the NITZ string so 109 * we can fix the time zone once know the country. 110 */ 111 protected boolean mNeedFixZone = false; 112 private int mZoneOffset; 113 private boolean mZoneDst; 114 private long mZoneTime; 115 protected boolean mGotCountryCode = false; 116 String mSavedTimeZone; 117 long mSavedTime; 118 long mSavedAtTime; 119 120 /** Wake lock used while setting time of day. */ 121 private PowerManager.WakeLock mWakeLock; 122 private static final String WAKELOCK_TAG = "ServiceStateTracker"; 123 124 /** Contains the name of the registered network in CDMA (either ONS or ERI text). */ 125 protected String mCurPlmn = null; 126 127 protected String mMdn; 128 protected int mHomeSystemId[] = null; 129 protected int mHomeNetworkId[] = null; 130 protected String mMin; 131 protected String mPrlVersion; 132 protected boolean mIsMinInfoReady = false; 133 134 private boolean mIsEriTextLoaded = false; 135 protected boolean mIsSubscriptionFromRuim = false; 136 private CdmaSubscriptionSourceManager mCdmaSSM; 137 138 /* Used only for debugging purposes. */ 139 private String mRegistrationDeniedReason; 140 141 private ContentResolver mCr; 142 private String mCurrentCarrier = null; 143 144 private ContentObserver mAutoTimeObserver = new ContentObserver(new Handler()) { 145 @Override 146 public void onChange(boolean selfChange) { 147 if (DBG) log("Auto time state changed"); 148 revertToNitzTime(); 149 } 150 }; 151 152 private ContentObserver mAutoTimeZoneObserver = new ContentObserver(new Handler()) { 153 @Override 154 public void onChange(boolean selfChange) { 155 if (DBG) log("Auto time zone state changed"); 156 revertToNitzTimeZone(); 157 } 158 }; 159 160 public CdmaServiceStateTracker(CDMAPhone phone) { 161 this(phone, new CellInfoCdma()); 162 } 163 164 protected CdmaServiceStateTracker(CDMAPhone phone, CellInfo cellInfo) { 165 super(phone, phone.mCi, cellInfo); 166 167 mPhone = phone; 168 mCr = phone.getContext().getContentResolver(); 169 mCellLoc = new CdmaCellLocation(); 170 mNewCellLoc = new CdmaCellLocation(); 171 172 mCdmaSSM = CdmaSubscriptionSourceManager.getInstance(phone.getContext(), mCi, this, 173 EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED, null); 174 mIsSubscriptionFromRuim = (mCdmaSSM.getCdmaSubscriptionSource() == 175 CdmaSubscriptionSourceManager.SUBSCRIPTION_FROM_RUIM); 176 177 PowerManager powerManager = 178 (PowerManager)phone.getContext().getSystemService(Context.POWER_SERVICE); 179 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG); 180 181 mCi.registerForRadioStateChanged(this, EVENT_RADIO_STATE_CHANGED, null); 182 183 mCi.registerForVoiceNetworkStateChanged(this, EVENT_NETWORK_STATE_CHANGED_CDMA, null); 184 mCi.setOnNITZTime(this, EVENT_NITZ_TIME, null); 185 186 mCi.registerForCdmaPrlChanged(this, EVENT_CDMA_PRL_VERSION_CHANGED, null); 187 phone.registerForEriFileLoaded(this, EVENT_ERI_FILE_LOADED, null); 188 mCi.registerForCdmaOtaProvision(this,EVENT_OTA_PROVISION_STATUS_CHANGE, null); 189 190 // System setting property AIRPLANE_MODE_ON is set in Settings. 191 int airplaneMode = Settings.Global.getInt(mCr, Settings.Global.AIRPLANE_MODE_ON, 0); 192 mDesiredPowerState = ! (airplaneMode > 0); 193 194 mCr.registerContentObserver( 195 Settings.Global.getUriFor(Settings.Global.AUTO_TIME), true, 196 mAutoTimeObserver); 197 mCr.registerContentObserver( 198 Settings.Global.getUriFor(Settings.Global.AUTO_TIME_ZONE), true, 199 mAutoTimeZoneObserver); 200 setSignalStrengthDefaultValues(); 201 } 202 203 @Override 204 public void dispose() { 205 checkCorrectThread(); 206 log("ServiceStateTracker dispose"); 207 208 // Unregister for all events. 209 mCi.unregisterForRadioStateChanged(this); 210 mCi.unregisterForVoiceNetworkStateChanged(this); 211 mCi.unregisterForCdmaOtaProvision(this); 212 mPhone.unregisterForEriFileLoaded(this); 213 if (mUiccApplcation != null) {mUiccApplcation.unregisterForReady(this);} 214 if (mIccRecords != null) {mIccRecords.unregisterForRecordsLoaded(this);} 215 mCi.unSetOnNITZTime(this); 216 mCr.unregisterContentObserver(mAutoTimeObserver); 217 mCr.unregisterContentObserver(mAutoTimeZoneObserver); 218 mCdmaSSM.dispose(this); 219 mCi.unregisterForCdmaPrlChanged(this); 220 super.dispose(); 221 } 222 223 @Override 224 protected void finalize() { 225 if (DBG) log("CdmaServiceStateTracker finalized"); 226 } 227 228 /** 229 * Registration point for subscription info ready 230 * @param h handler to notify 231 * @param what what code of message when delivered 232 * @param obj placed in Message.obj 233 */ 234 public void registerForSubscriptionInfoReady(Handler h, int what, Object obj) { 235 Registrant r = new Registrant(h, what, obj); 236 mCdmaForSubscriptionInfoReadyRegistrants.add(r); 237 238 if (isMinInfoReady()) { 239 r.notifyRegistrant(); 240 } 241 } 242 243 public void unregisterForSubscriptionInfoReady(Handler h) { 244 mCdmaForSubscriptionInfoReadyRegistrants.remove(h); 245 } 246 247 /** 248 * Save current source of cdma subscription 249 * @param source - 1 for NV, 0 for RUIM 250 */ 251 private void saveCdmaSubscriptionSource(int source) { 252 log("Storing cdma subscription source: " + source); 253 Settings.Global.putInt(mPhone.getContext().getContentResolver(), 254 Settings.Global.CDMA_SUBSCRIPTION_MODE, 255 source ); 256 } 257 258 private void getSubscriptionInfoAndStartPollingThreads() { 259 mCi.getCDMASubscription(obtainMessage(EVENT_POLL_STATE_CDMA_SUBSCRIPTION)); 260 261 // Get Registration Information 262 pollState(); 263 } 264 265 @Override 266 public void handleMessage (Message msg) { 267 AsyncResult ar; 268 int[] ints; 269 String[] strings; 270 271 if (!mPhone.mIsTheCurrentActivePhone) { 272 loge("Received message " + msg + "[" + msg.what + "]" + 273 " while being destroyed. Ignoring."); 274 return; 275 } 276 277 switch (msg.what) { 278 case EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED: 279 handleCdmaSubscriptionSource(mCdmaSSM.getCdmaSubscriptionSource()); 280 break; 281 282 case EVENT_RUIM_READY: 283 // TODO: Consider calling setCurrentPreferredNetworkType as we do in GsmSST. 284 // cm.setCurrentPreferredNetworkType(); 285 286 if (mPhone.getLteOnCdmaMode() == PhoneConstants.LTE_ON_CDMA_TRUE) { 287 // Subscription will be read from SIM I/O 288 if (DBG) log("Receive EVENT_RUIM_READY"); 289 pollState(); 290 } else { 291 if (DBG) log("Receive EVENT_RUIM_READY and Send Request getCDMASubscription."); 292 getSubscriptionInfoAndStartPollingThreads(); 293 } 294 mPhone.prepareEri(); 295 break; 296 297 case EVENT_NV_READY: 298 updatePhoneObject(); 299 300 // For Non-RUIM phones, the subscription information is stored in 301 // Non Volatile. Here when Non-Volatile is ready, we can poll the CDMA 302 // subscription info. 303 getSubscriptionInfoAndStartPollingThreads(); 304 break; 305 306 case EVENT_RADIO_STATE_CHANGED: 307 if(mCi.getRadioState() == RadioState.RADIO_ON) { 308 handleCdmaSubscriptionSource(mCdmaSSM.getCdmaSubscriptionSource()); 309 310 // Signal strength polling stops when radio is off. 311 queueNextSignalStrengthPoll(); 312 } 313 // This will do nothing in the 'radio not available' case. 314 setPowerStateToDesired(); 315 pollState(); 316 break; 317 318 case EVENT_NETWORK_STATE_CHANGED_CDMA: 319 pollState(); 320 break; 321 322 case EVENT_GET_SIGNAL_STRENGTH: 323 // This callback is called when signal strength is polled 324 // all by itself. 325 326 if (!(mCi.getRadioState().isOn())) { 327 // Polling will continue when radio turns back on. 328 return; 329 } 330 ar = (AsyncResult) msg.obj; 331 onSignalStrengthResult(ar, false); 332 queueNextSignalStrengthPoll(); 333 334 break; 335 336 case EVENT_GET_LOC_DONE_CDMA: 337 ar = (AsyncResult) msg.obj; 338 339 if (ar.exception == null) { 340 String states[] = (String[])ar.result; 341 int baseStationId = -1; 342 int baseStationLatitude = CdmaCellLocation.INVALID_LAT_LONG; 343 int baseStationLongitude = CdmaCellLocation.INVALID_LAT_LONG; 344 int systemId = -1; 345 int networkId = -1; 346 347 if (states.length > 9) { 348 try { 349 if (states[4] != null) { 350 baseStationId = Integer.parseInt(states[4]); 351 } 352 if (states[5] != null) { 353 baseStationLatitude = Integer.parseInt(states[5]); 354 } 355 if (states[6] != null) { 356 baseStationLongitude = Integer.parseInt(states[6]); 357 } 358 // Some carriers only return lat-lngs of 0,0 359 if (baseStationLatitude == 0 && baseStationLongitude == 0) { 360 baseStationLatitude = CdmaCellLocation.INVALID_LAT_LONG; 361 baseStationLongitude = CdmaCellLocation.INVALID_LAT_LONG; 362 } 363 if (states[8] != null) { 364 systemId = Integer.parseInt(states[8]); 365 } 366 if (states[9] != null) { 367 networkId = Integer.parseInt(states[9]); 368 } 369 } catch (NumberFormatException ex) { 370 loge("error parsing cell location data: " + ex); 371 } 372 } 373 374 mCellLoc.setCellLocationData(baseStationId, baseStationLatitude, 375 baseStationLongitude, systemId, networkId); 376 mPhone.notifyLocationChanged(); 377 } 378 379 // Release any temporary cell lock, which could have been 380 // acquired to allow a single-shot location update. 381 disableSingleLocationUpdate(); 382 break; 383 384 case EVENT_POLL_STATE_REGISTRATION_CDMA: 385 case EVENT_POLL_STATE_OPERATOR_CDMA: 386 case EVENT_POLL_STATE_GPRS: 387 ar = (AsyncResult) msg.obj; 388 handlePollStateResult(msg.what, ar); 389 break; 390 391 case EVENT_POLL_STATE_CDMA_SUBSCRIPTION: // Handle RIL_CDMA_SUBSCRIPTION 392 ar = (AsyncResult) msg.obj; 393 394 if (ar.exception == null) { 395 String cdmaSubscription[] = (String[])ar.result; 396 if (cdmaSubscription != null && cdmaSubscription.length >= 5) { 397 mMdn = cdmaSubscription[0]; 398 parseSidNid(cdmaSubscription[1], cdmaSubscription[2]); 399 400 mMin = cdmaSubscription[3]; 401 mPrlVersion = cdmaSubscription[4]; 402 if (DBG) log("GET_CDMA_SUBSCRIPTION: MDN=" + mMdn); 403 404 mIsMinInfoReady = true; 405 406 updateOtaspState(); 407 if (!mIsSubscriptionFromRuim && mIccRecords != null) { 408 if (DBG) { 409 log("GET_CDMA_SUBSCRIPTION set imsi in mIccRecords"); 410 } 411 mIccRecords.setImsi(getImsi()); 412 } else { 413 if (DBG) { 414 log("GET_CDMA_SUBSCRIPTION either mIccRecords is null or NV type device" + 415 " - not setting Imsi in mIccRecords"); 416 } 417 } 418 } else { 419 if (DBG) { 420 log("GET_CDMA_SUBSCRIPTION: error parsing cdmaSubscription params num=" 421 + cdmaSubscription.length); 422 } 423 } 424 } 425 break; 426 427 case EVENT_POLL_SIGNAL_STRENGTH: 428 // Just poll signal strength...not part of pollState() 429 430 mCi.getSignalStrength(obtainMessage(EVENT_GET_SIGNAL_STRENGTH)); 431 break; 432 433 case EVENT_NITZ_TIME: 434 ar = (AsyncResult) msg.obj; 435 436 String nitzString = (String)((Object[])ar.result)[0]; 437 long nitzReceiveTime = ((Long)((Object[])ar.result)[1]).longValue(); 438 439 setTimeFromNITZString(nitzString, nitzReceiveTime); 440 break; 441 442 case EVENT_SIGNAL_STRENGTH_UPDATE: 443 // This is a notification from CommandsInterface.setOnSignalStrengthUpdate. 444 445 ar = (AsyncResult) msg.obj; 446 447 // The radio is telling us about signal strength changes, 448 // so we don't have to ask it. 449 mDontPollSignalStrength = true; 450 451 onSignalStrengthResult(ar, false); 452 break; 453 454 case EVENT_RUIM_RECORDS_LOADED: 455 log("EVENT_RUIM_RECORDS_LOADED: what=" + msg.what); 456 updatePhoneObject(); 457 updateSpnDisplay(); 458 break; 459 460 case EVENT_LOCATION_UPDATES_ENABLED: 461 ar = (AsyncResult) msg.obj; 462 463 if (ar.exception == null) { 464 mCi.getVoiceRegistrationState(obtainMessage(EVENT_GET_LOC_DONE_CDMA, null)); 465 } 466 break; 467 468 case EVENT_ERI_FILE_LOADED: 469 // Repoll the state once the ERI file has been loaded. 470 if (DBG) log("[CdmaServiceStateTracker] ERI file has been loaded, repolling."); 471 pollState(); 472 break; 473 474 case EVENT_OTA_PROVISION_STATUS_CHANGE: 475 ar = (AsyncResult)msg.obj; 476 if (ar.exception == null) { 477 ints = (int[]) ar.result; 478 int otaStatus = ints[0]; 479 if (otaStatus == Phone.CDMA_OTA_PROVISION_STATUS_COMMITTED 480 || otaStatus == Phone.CDMA_OTA_PROVISION_STATUS_OTAPA_STOPPED) { 481 if (DBG) log("EVENT_OTA_PROVISION_STATUS_CHANGE: Complete, Reload MDN"); 482 mCi.getCDMASubscription( obtainMessage(EVENT_POLL_STATE_CDMA_SUBSCRIPTION)); 483 } 484 } 485 break; 486 487 case EVENT_CDMA_PRL_VERSION_CHANGED: 488 ar = (AsyncResult)msg.obj; 489 if (ar.exception == null) { 490 ints = (int[]) ar.result; 491 mPrlVersion = Integer.toString(ints[0]); 492 } 493 break; 494 495 default: 496 super.handleMessage(msg); 497 break; 498 } 499 } 500 501 //***** Private Instance Methods 502 503 private void handleCdmaSubscriptionSource(int newSubscriptionSource) { 504 log("Subscription Source : " + newSubscriptionSource); 505 mIsSubscriptionFromRuim = 506 (newSubscriptionSource == CdmaSubscriptionSourceManager.SUBSCRIPTION_FROM_RUIM); 507 saveCdmaSubscriptionSource(newSubscriptionSource); 508 if (!mIsSubscriptionFromRuim) { 509 // NV is ready when subscription source is NV 510 sendMessage(obtainMessage(EVENT_NV_READY)); 511 } 512 } 513 514 @Override 515 protected void setPowerStateToDesired() { 516 // If we want it on and it's off, turn it on 517 if (mDesiredPowerState 518 && mCi.getRadioState() == CommandsInterface.RadioState.RADIO_OFF) { 519 mCi.setRadioPower(true, null); 520 } else if (!mDesiredPowerState && mCi.getRadioState().isOn()) { 521 DcTrackerBase dcTracker = mPhone.mDcTracker; 522 523 // If it's on and available and we want it off gracefully 524 powerOffRadioSafely(dcTracker); 525 } // Otherwise, we're in the desired state 526 } 527 528 @Override 529 protected void updateSpnDisplay() { 530 // mOperatorAlphaLong contains the ERI text 531 String plmn = mSS.getOperatorAlphaLong(); 532 if (!TextUtils.equals(plmn, mCurPlmn)) { 533 // Allow A blank plmn, "" to set showPlmn to true. Previously, we 534 // would set showPlmn to true only if plmn was not empty, i.e. was not 535 // null and not blank. But this would cause us to incorrectly display 536 // "No Service". Now showPlmn is set to true for any non null string. 537 boolean showPlmn = plmn != null; 538 if (DBG) { 539 log(String.format("updateSpnDisplay: changed sending intent" + 540 " showPlmn='%b' plmn='%s'", showPlmn, plmn)); 541 } 542 Intent intent = new Intent(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION); 543 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); 544 intent.putExtra(TelephonyIntents.EXTRA_SHOW_SPN, false); 545 intent.putExtra(TelephonyIntents.EXTRA_SPN, ""); 546 intent.putExtra(TelephonyIntents.EXTRA_SHOW_PLMN, showPlmn); 547 intent.putExtra(TelephonyIntents.EXTRA_PLMN, plmn); 548 mPhone.getContext().sendStickyBroadcastAsUser(intent, UserHandle.ALL); 549 } 550 551 mCurPlmn = plmn; 552 } 553 554 @Override 555 protected Phone getPhone() { 556 return mPhone; 557 } 558 559 /** 560 * Hanlde the PollStateResult message 561 */ 562 protected void handlePollStateResultMessage(int what, AsyncResult ar){ 563 int ints[]; 564 String states[]; 565 switch (what) { 566 case EVENT_POLL_STATE_GPRS: { 567 states = (String[])ar.result; 568 if (DBG) { 569 log("handlePollStateResultMessage: EVENT_POLL_STATE_GPRS states.length=" + 570 states.length + " states=" + states); 571 } 572 573 int regState = ServiceState.RIL_REG_STATE_UNKNOWN; 574 int dataRadioTechnology = 0; 575 576 if (states.length > 0) { 577 try { 578 regState = Integer.parseInt(states[0]); 579 580 // states[3] (if present) is the current radio technology 581 if (states.length >= 4 && states[3] != null) { 582 dataRadioTechnology = Integer.parseInt(states[3]); 583 } 584 } catch (NumberFormatException ex) { 585 loge("handlePollStateResultMessage: error parsing GprsRegistrationState: " 586 + ex); 587 } 588 } 589 590 int dataRegState = regCodeToServiceState(regState); 591 mNewSS.setDataRegState(dataRegState); 592 mNewSS.setRilDataRadioTechnology(dataRadioTechnology); 593 if (DBG) { 594 log("handlPollStateResultMessage: cdma setDataRegState=" + dataRegState 595 + " regState=" + regState 596 + " dataRadioTechnology=" + dataRadioTechnology); 597 } 598 break; 599 } 600 601 case EVENT_POLL_STATE_REGISTRATION_CDMA: // Handle RIL_REQUEST_REGISTRATION_STATE. 602 states = (String[])ar.result; 603 604 int registrationState = 4; //[0] registrationState 605 int radioTechnology = -1; //[3] radioTechnology 606 int baseStationId = -1; //[4] baseStationId 607 //[5] baseStationLatitude 608 int baseStationLatitude = CdmaCellLocation.INVALID_LAT_LONG; 609 //[6] baseStationLongitude 610 int baseStationLongitude = CdmaCellLocation.INVALID_LAT_LONG; 611 int cssIndicator = 0; //[7] init with 0, because it is treated as a boolean 612 int systemId = 0; //[8] systemId 613 int networkId = 0; //[9] networkId 614 int roamingIndicator = -1; //[10] Roaming indicator 615 int systemIsInPrl = 0; //[11] Indicates if current system is in PRL 616 int defaultRoamingIndicator = 0; //[12] Is default roaming indicator from PRL 617 int reasonForDenial = 0; //[13] Denial reason if registrationState = 3 618 619 if (states.length >= 14) { 620 try { 621 if (states[0] != null) { 622 registrationState = Integer.parseInt(states[0]); 623 } 624 if (states[3] != null) { 625 radioTechnology = Integer.parseInt(states[3]); 626 } 627 if (states[4] != null) { 628 baseStationId = Integer.parseInt(states[4]); 629 } 630 if (states[5] != null) { 631 baseStationLatitude = Integer.parseInt(states[5]); 632 } 633 if (states[6] != null) { 634 baseStationLongitude = Integer.parseInt(states[6]); 635 } 636 // Some carriers only return lat-lngs of 0,0 637 if (baseStationLatitude == 0 && baseStationLongitude == 0) { 638 baseStationLatitude = CdmaCellLocation.INVALID_LAT_LONG; 639 baseStationLongitude = CdmaCellLocation.INVALID_LAT_LONG; 640 } 641 if (states[7] != null) { 642 cssIndicator = Integer.parseInt(states[7]); 643 } 644 if (states[8] != null) { 645 systemId = Integer.parseInt(states[8]); 646 } 647 if (states[9] != null) { 648 networkId = Integer.parseInt(states[9]); 649 } 650 if (states[10] != null) { 651 roamingIndicator = Integer.parseInt(states[10]); 652 } 653 if (states[11] != null) { 654 systemIsInPrl = Integer.parseInt(states[11]); 655 } 656 if (states[12] != null) { 657 defaultRoamingIndicator = Integer.parseInt(states[12]); 658 } 659 if (states[13] != null) { 660 reasonForDenial = Integer.parseInt(states[13]); 661 } 662 } catch (NumberFormatException ex) { 663 loge("EVENT_POLL_STATE_REGISTRATION_CDMA: error parsing: " + ex); 664 } 665 } else { 666 throw new RuntimeException("Warning! Wrong number of parameters returned from " 667 + "RIL_REQUEST_REGISTRATION_STATE: expected 14 or more " 668 + "strings and got " + states.length + " strings"); 669 } 670 671 mRegistrationState = registrationState; 672 // When registration state is roaming and TSB58 673 // roaming indicator is not in the carrier-specified 674 // list of ERIs for home system, mCdmaRoaming is true. 675 mCdmaRoaming = 676 regCodeIsRoaming(registrationState) && !isRoamIndForHomeSystem(states[10]); 677 mNewSS.setState (regCodeToServiceState(registrationState)); 678 679 mNewSS.setRilVoiceRadioTechnology(radioTechnology); 680 681 mNewSS.setCssIndicator(cssIndicator); 682 mNewSS.setSystemAndNetworkId(systemId, networkId); 683 mRoamingIndicator = roamingIndicator; 684 mIsInPrl = (systemIsInPrl == 0) ? false : true; 685 mDefaultRoamingIndicator = defaultRoamingIndicator; 686 687 688 // Values are -1 if not available. 689 mNewCellLoc.setCellLocationData(baseStationId, baseStationLatitude, 690 baseStationLongitude, systemId, networkId); 691 692 if (reasonForDenial == 0) { 693 mRegistrationDeniedReason = ServiceStateTracker.REGISTRATION_DENIED_GEN; 694 } else if (reasonForDenial == 1) { 695 mRegistrationDeniedReason = ServiceStateTracker.REGISTRATION_DENIED_AUTH; 696 } else { 697 mRegistrationDeniedReason = ""; 698 } 699 700 if (mRegistrationState == 3) { 701 if (DBG) log("Registration denied, " + mRegistrationDeniedReason); 702 } 703 break; 704 705 case EVENT_POLL_STATE_OPERATOR_CDMA: // Handle RIL_REQUEST_OPERATOR 706 String opNames[] = (String[])ar.result; 707 708 if (opNames != null && opNames.length >= 3) { 709 // If the NUMERIC field isn't valid use PROPERTY_CDMA_HOME_OPERATOR_NUMERIC 710 if ((opNames[2] == null) || (opNames[2].length() < 5) 711 || ("00000".equals(opNames[2]))) { 712 opNames[2] = SystemProperties.get( 713 CDMAPhone.PROPERTY_CDMA_HOME_OPERATOR_NUMERIC, "00000"); 714 if (DBG) { 715 log("RIL_REQUEST_OPERATOR.response[2], the numeric, " + 716 " is bad. Using SystemProperties '" + 717 CDMAPhone.PROPERTY_CDMA_HOME_OPERATOR_NUMERIC + 718 "'= " + opNames[2]); 719 } 720 } 721 722 if (!mIsSubscriptionFromRuim) { 723 // In CDMA in case on NV, the ss.mOperatorAlphaLong is set later with the 724 // ERI text, so here it is ignored what is coming from the modem. 725 mNewSS.setOperatorName(null, opNames[1], opNames[2]); 726 } else { 727 mNewSS.setOperatorName(opNames[0], opNames[1], opNames[2]); 728 } 729 } else { 730 if (DBG) log("EVENT_POLL_STATE_OPERATOR_CDMA: error parsing opNames"); 731 } 732 break; 733 734 735 default: 736 737 738 loge("handlePollStateResultMessage: RIL response handle in wrong phone!" 739 + " Expected CDMA RIL request and get GSM RIL request."); 740 break; 741 } 742 } 743 744 /** 745 * Handle the result of one of the pollState() - related requests 746 */ 747 @Override 748 protected void handlePollStateResult(int what, AsyncResult ar) { 749 // Ignore stale requests from last poll. 750 if (ar.userObj != mPollingContext) return; 751 752 if (ar.exception != null) { 753 CommandException.Error err=null; 754 755 if (ar.exception instanceof CommandException) { 756 err = ((CommandException)(ar.exception)).getCommandError(); 757 } 758 759 if (err == CommandException.Error.RADIO_NOT_AVAILABLE) { 760 // Radio has crashed or turned off. 761 cancelPollState(); 762 return; 763 } 764 765 if (!mCi.getRadioState().isOn()) { 766 // Radio has crashed or turned off. 767 cancelPollState(); 768 return; 769 } 770 771 if (err != CommandException.Error.OP_NOT_ALLOWED_BEFORE_REG_NW) { 772 loge("handlePollStateResult: RIL returned an error where it must succeed" 773 + ar.exception); 774 } 775 } else try { 776 handlePollStateResultMessage(what, ar); 777 } catch (RuntimeException ex) { 778 loge("handlePollStateResult: Exception while polling service state. " 779 + "Probably malformed RIL response." + ex); 780 } 781 782 mPollingContext[0]--; 783 784 if (mPollingContext[0] == 0) { 785 boolean namMatch = false; 786 if (!isSidsAllZeros() && isHomeSid(mNewSS.getSystemId())) { 787 namMatch = true; 788 } 789 790 // Setting SS Roaming (general) 791 if (mIsSubscriptionFromRuim) { 792 mNewSS.setRoaming(isRoamingBetweenOperators(mCdmaRoaming, mNewSS)); 793 } else { 794 mNewSS.setRoaming(mCdmaRoaming); 795 } 796 797 // Setting SS CdmaRoamingIndicator and CdmaDefaultRoamingIndicator 798 mNewSS.setCdmaDefaultRoamingIndicator(mDefaultRoamingIndicator); 799 mNewSS.setCdmaRoamingIndicator(mRoamingIndicator); 800 boolean isPrlLoaded = true; 801 if (TextUtils.isEmpty(mPrlVersion)) { 802 isPrlLoaded = false; 803 } 804 if (!isPrlLoaded || (mNewSS.getRilVoiceRadioTechnology() 805 == ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN)) { 806 log("Turn off roaming indicator if !isPrlLoaded or voice RAT is unknown"); 807 mNewSS.setCdmaRoamingIndicator(EriInfo.ROAMING_INDICATOR_OFF); 808 } else if (!isSidsAllZeros()) { 809 if (!namMatch && !mIsInPrl) { 810 // Use default 811 mNewSS.setCdmaRoamingIndicator(mDefaultRoamingIndicator); 812 } else if (namMatch && !mIsInPrl) { 813 // TODO this will be removed when we handle roaming on LTE on CDMA+LTE phones 814 if (mNewSS.getRilVoiceRadioTechnology() 815 == ServiceState.RIL_RADIO_TECHNOLOGY_LTE) { 816 log("Turn off roaming indicator as voice is LTE"); 817 mNewSS.setCdmaRoamingIndicator(EriInfo.ROAMING_INDICATOR_OFF); 818 } else { 819 mNewSS.setCdmaRoamingIndicator(EriInfo.ROAMING_INDICATOR_FLASH); 820 } 821 } else if (!namMatch && mIsInPrl) { 822 // Use the one from PRL/ERI 823 mNewSS.setCdmaRoamingIndicator(mRoamingIndicator); 824 } else { 825 // It means namMatch && mIsInPrl 826 if ((mRoamingIndicator <= 2)) { 827 mNewSS.setCdmaRoamingIndicator(EriInfo.ROAMING_INDICATOR_OFF); 828 } else { 829 // Use the one from PRL/ERI 830 mNewSS.setCdmaRoamingIndicator(mRoamingIndicator); 831 } 832 } 833 } 834 835 int roamingIndicator = mNewSS.getCdmaRoamingIndicator(); 836 mNewSS.setCdmaEriIconIndex(mPhone.mEriManager.getCdmaEriIconIndex(roamingIndicator, 837 mDefaultRoamingIndicator)); 838 mNewSS.setCdmaEriIconMode(mPhone.mEriManager.getCdmaEriIconMode(roamingIndicator, 839 mDefaultRoamingIndicator)); 840 841 // NOTE: Some operator may require overriding mCdmaRoaming 842 // (set by the modem), depending on the mRoamingIndicator. 843 844 if (DBG) { 845 log("Set CDMA Roaming Indicator to: " + mNewSS.getCdmaRoamingIndicator() 846 + ". mCdmaRoaming = " + mCdmaRoaming + ", isPrlLoaded = " + isPrlLoaded 847 + ". namMatch = " + namMatch + " , mIsInPrl = " + mIsInPrl 848 + ", mRoamingIndicator = " + mRoamingIndicator 849 + ", mDefaultRoamingIndicator= " + mDefaultRoamingIndicator); 850 } 851 pollStateDone(); 852 } 853 854 } 855 856 protected void setSignalStrengthDefaultValues() { 857 mSignalStrength = new SignalStrength( false); 858 } 859 860 /** 861 * A complete "service state" from our perspective is 862 * composed of a handful of separate requests to the radio. 863 * 864 * We make all of these requests at once, but then abandon them 865 * and start over again if the radio notifies us that some 866 * event has changed 867 */ 868 protected void 869 pollState() { 870 mPollingContext = new int[1]; 871 mPollingContext[0] = 0; 872 873 switch (mCi.getRadioState()) { 874 case RADIO_UNAVAILABLE: 875 mNewSS.setStateOutOfService(); 876 mNewCellLoc.setStateInvalid(); 877 setSignalStrengthDefaultValues(); 878 mGotCountryCode = false; 879 880 pollStateDone(); 881 break; 882 883 case RADIO_OFF: 884 mNewSS.setStateOff(); 885 mNewCellLoc.setStateInvalid(); 886 setSignalStrengthDefaultValues(); 887 mGotCountryCode = false; 888 889 pollStateDone(); 890 break; 891 892 default: 893 // Issue all poll-related commands at once, then count 894 // down the responses which are allowed to arrive 895 // out-of-order. 896 897 mPollingContext[0]++; 898 // RIL_REQUEST_OPERATOR is necessary for CDMA 899 mCi.getOperator( 900 obtainMessage(EVENT_POLL_STATE_OPERATOR_CDMA, mPollingContext)); 901 902 mPollingContext[0]++; 903 // RIL_REQUEST_VOICE_REGISTRATION_STATE is necessary for CDMA 904 mCi.getVoiceRegistrationState( 905 obtainMessage(EVENT_POLL_STATE_REGISTRATION_CDMA, mPollingContext)); 906 907 mPollingContext[0]++; 908 // RIL_REQUEST_DATA_REGISTRATION_STATE 909 mCi.getDataRegistrationState(obtainMessage(EVENT_POLL_STATE_GPRS, 910 mPollingContext)); 911 break; 912 } 913 } 914 915 protected void fixTimeZone(String isoCountryCode) { 916 TimeZone zone = null; 917 // If the offset is (0, false) and the time zone property 918 // is set, use the time zone property rather than GMT. 919 String zoneName = SystemProperties.get(TIMEZONE_PROPERTY); 920 if (DBG) { 921 log("fixTimeZone zoneName='" + zoneName + 922 "' mZoneOffset=" + mZoneOffset + " mZoneDst=" + mZoneDst + 923 " iso-cc='" + isoCountryCode + 924 "' iso-cc-idx=" + Arrays.binarySearch(GMT_COUNTRY_CODES, isoCountryCode)); 925 } 926 if ((mZoneOffset == 0) && (mZoneDst == false) && (zoneName != null) 927 && (zoneName.length() > 0) 928 && (Arrays.binarySearch(GMT_COUNTRY_CODES, isoCountryCode) < 0)) { 929 // For NITZ string without time zone, 930 // need adjust time to reflect default time zone setting 931 zone = TimeZone.getDefault(); 932 if (mNeedFixZone) { 933 long ctm = System.currentTimeMillis(); 934 long tzOffset = zone.getOffset(ctm); 935 if (DBG) { 936 log("fixTimeZone: tzOffset=" + tzOffset + 937 " ltod=" + TimeUtils.logTimeOfDay(ctm)); 938 } 939 if (getAutoTime()) { 940 long adj = ctm - tzOffset; 941 if (DBG) log("fixTimeZone: adj ltod=" + TimeUtils.logTimeOfDay(adj)); 942 setAndBroadcastNetworkSetTime(adj); 943 } else { 944 // Adjust the saved NITZ time to account for tzOffset. 945 mSavedTime = mSavedTime - tzOffset; 946 if (DBG) log("fixTimeZone: adj mSavedTime=" + mSavedTime); 947 } 948 } 949 if (DBG) log("fixTimeZone: using default TimeZone"); 950 } else if (isoCountryCode.equals("")) { 951 // Country code not found. This is likely a test network. 952 // Get a TimeZone based only on the NITZ parameters (best guess). 953 zone = getNitzTimeZone(mZoneOffset, mZoneDst, mZoneTime); 954 if (DBG) log("fixTimeZone: using NITZ TimeZone"); 955 } else { 956 zone = TimeUtils.getTimeZone(mZoneOffset, mZoneDst, mZoneTime, isoCountryCode); 957 if (DBG) log("fixTimeZone: using getTimeZone(off, dst, time, iso)"); 958 } 959 960 mNeedFixZone = false; 961 962 if (zone != null) { 963 log("fixTimeZone: zone != null zone.getID=" + zone.getID()); 964 if (getAutoTimeZone()) { 965 setAndBroadcastNetworkSetTimeZone(zone.getID()); 966 } else { 967 log("fixTimeZone: skip changing zone as getAutoTimeZone was false"); 968 } 969 saveNitzTimeZone(zone.getID()); 970 } else { 971 log("fixTimeZone: zone == null, do nothing for zone"); 972 } 973 } 974 975 protected void pollStateDone() { 976 if (DBG) log("pollStateDone: cdma oldSS=[" + mSS + "] newSS=[" + mNewSS + "]"); 977 978 if (Build.IS_DEBUGGABLE && SystemProperties.getBoolean(PROP_FORCE_ROAMING, false)) { 979 mNewSS.setRoaming(true); 980 } 981 982 useDataRegStateForDataOnlyDevices(); 983 984 boolean hasRegistered = 985 mSS.getVoiceRegState() != ServiceState.STATE_IN_SERVICE 986 && mNewSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE; 987 988 boolean hasDeregistered = 989 mSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE 990 && mNewSS.getVoiceRegState() != ServiceState.STATE_IN_SERVICE; 991 992 boolean hasCdmaDataConnectionAttached = 993 mSS.getDataRegState() != ServiceState.STATE_IN_SERVICE 994 && mNewSS.getDataRegState() == ServiceState.STATE_IN_SERVICE; 995 996 boolean hasCdmaDataConnectionDetached = 997 mSS.getDataRegState() == ServiceState.STATE_IN_SERVICE 998 && mNewSS.getDataRegState() != ServiceState.STATE_IN_SERVICE; 999 1000 boolean hasCdmaDataConnectionChanged = 1001 mSS.getDataRegState() != mNewSS.getDataRegState(); 1002 1003 boolean hasRilVoiceRadioTechnologyChanged = 1004 mSS.getRilVoiceRadioTechnology() != mNewSS.getRilVoiceRadioTechnology(); 1005 1006 boolean hasRilDataRadioTechnologyChanged = 1007 mSS.getRilDataRadioTechnology() != mNewSS.getRilDataRadioTechnology(); 1008 1009 boolean hasChanged = !mNewSS.equals(mSS); 1010 1011 boolean hasRoamingOn = !mSS.getRoaming() && mNewSS.getRoaming(); 1012 1013 boolean hasRoamingOff = mSS.getRoaming() && !mNewSS.getRoaming(); 1014 1015 boolean hasLocationChanged = !mNewCellLoc.equals(mCellLoc); 1016 1017 // Add an event log when connection state changes 1018 if (mSS.getVoiceRegState() != mNewSS.getVoiceRegState() || 1019 mSS.getDataRegState() != mNewSS.getDataRegState()) { 1020 EventLog.writeEvent(EventLogTags.CDMA_SERVICE_STATE_CHANGE, 1021 mSS.getVoiceRegState(), mSS.getDataRegState(), 1022 mNewSS.getVoiceRegState(), mNewSS.getDataRegState()); 1023 } 1024 1025 ServiceState tss; 1026 tss = mSS; 1027 mSS = mNewSS; 1028 mNewSS = tss; 1029 // clean slate for next time 1030 mNewSS.setStateOutOfService(); 1031 1032 CdmaCellLocation tcl = mCellLoc; 1033 mCellLoc = mNewCellLoc; 1034 mNewCellLoc = tcl; 1035 1036 if (hasRilVoiceRadioTechnologyChanged) { 1037 updatePhoneObject(); 1038 } 1039 1040 if (hasRilDataRadioTechnologyChanged) { 1041 mPhone.setSystemProperty(TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE, 1042 ServiceState.rilRadioTechnologyToString(mSS.getRilDataRadioTechnology())); 1043 } 1044 1045 if (hasRegistered) { 1046 mNetworkAttachedRegistrants.notifyRegistrants(); 1047 } 1048 1049 if (hasChanged) { 1050 if ((mCi.getRadioState().isOn()) && (!mIsSubscriptionFromRuim)) { 1051 String eriText; 1052 // Now the CDMAPhone sees the new ServiceState so it can get the new ERI text 1053 if (mSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE) { 1054 eriText = mPhone.getCdmaEriText(); 1055 } else { 1056 // Note that ServiceState.STATE_OUT_OF_SERVICE is valid used for 1057 // mRegistrationState 0,2,3 and 4 1058 eriText = mPhone.getContext().getText( 1059 com.android.internal.R.string.roamingTextSearching).toString(); 1060 } 1061 mSS.setOperatorAlphaLong(eriText); 1062 } 1063 1064 String operatorNumeric; 1065 1066 mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ALPHA, 1067 mSS.getOperatorAlphaLong()); 1068 1069 String prevOperatorNumeric = 1070 SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_NUMERIC, ""); 1071 operatorNumeric = mSS.getOperatorNumeric(); 1072 mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_NUMERIC, operatorNumeric); 1073 updateCarrierMccMncConfiguration(operatorNumeric, 1074 prevOperatorNumeric, mPhone.getContext()); 1075 if (operatorNumeric == null) { 1076 if (DBG) log("operatorNumeric is null"); 1077 mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY, ""); 1078 mGotCountryCode = false; 1079 } else { 1080 String isoCountryCode = ""; 1081 String mcc = operatorNumeric.substring(0, 3); 1082 try{ 1083 isoCountryCode = MccTable.countryCodeForMcc(Integer.parseInt( 1084 operatorNumeric.substring(0,3))); 1085 } catch ( NumberFormatException ex){ 1086 loge("pollStateDone: countryCodeForMcc error" + ex); 1087 } catch ( StringIndexOutOfBoundsException ex) { 1088 loge("pollStateDone: countryCodeForMcc error" + ex); 1089 } 1090 1091 mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY, 1092 isoCountryCode); 1093 mGotCountryCode = true; 1094 1095 if (shouldFixTimeZoneNow(mPhone, operatorNumeric, prevOperatorNumeric, 1096 mNeedFixZone)) { 1097 fixTimeZone(isoCountryCode); 1098 } 1099 } 1100 1101 mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISROAMING, 1102 mSS.getRoaming() ? "true" : "false"); 1103 1104 updateSpnDisplay(); 1105 mPhone.notifyServiceStateChanged(mSS); 1106 } 1107 1108 if (hasCdmaDataConnectionAttached) { 1109 mAttachedRegistrants.notifyRegistrants(); 1110 } 1111 1112 if (hasCdmaDataConnectionDetached) { 1113 mDetachedRegistrants.notifyRegistrants(); 1114 } 1115 1116 if (hasCdmaDataConnectionChanged || hasRilDataRadioTechnologyChanged) { 1117 notifyDataRegStateRilRadioTechnologyChanged(); 1118 mPhone.notifyDataConnection(null); 1119 } 1120 1121 if (hasRoamingOn) { 1122 mRoamingOnRegistrants.notifyRegistrants(); 1123 } 1124 1125 if (hasRoamingOff) { 1126 mRoamingOffRegistrants.notifyRegistrants(); 1127 } 1128 1129 if (hasLocationChanged) { 1130 mPhone.notifyLocationChanged(); 1131 } 1132 // TODO: Add CdmaCellIdenity updating, see CdmaLteServiceStateTracker. 1133 } 1134 1135 /** 1136 * Returns a TimeZone object based only on parameters from the NITZ string. 1137 */ 1138 private TimeZone getNitzTimeZone(int offset, boolean dst, long when) { 1139 TimeZone guess = findTimeZone(offset, dst, when); 1140 if (guess == null) { 1141 // Couldn't find a proper timezone. Perhaps the DST data is wrong. 1142 guess = findTimeZone(offset, !dst, when); 1143 } 1144 if (DBG) log("getNitzTimeZone returning " + (guess == null ? guess : guess.getID())); 1145 return guess; 1146 } 1147 1148 private TimeZone findTimeZone(int offset, boolean dst, long when) { 1149 int rawOffset = offset; 1150 if (dst) { 1151 rawOffset -= 3600000; 1152 } 1153 String[] zones = TimeZone.getAvailableIDs(rawOffset); 1154 TimeZone guess = null; 1155 Date d = new Date(when); 1156 for (String zone : zones) { 1157 TimeZone tz = TimeZone.getTimeZone(zone); 1158 if (tz.getOffset(when) == offset && 1159 tz.inDaylightTime(d) == dst) { 1160 guess = tz; 1161 break; 1162 } 1163 } 1164 1165 return guess; 1166 } 1167 1168 /** 1169 * TODO: This code is exactly the same as in GsmServiceStateTracker 1170 * and has a TODO to not poll signal strength if screen is off. 1171 * This code should probably be hoisted to the base class so 1172 * the fix, when added, works for both. 1173 */ 1174 private void 1175 queueNextSignalStrengthPoll() { 1176 if (mDontPollSignalStrength) { 1177 // The radio is telling us about signal strength changes 1178 // we don't have to ask it 1179 return; 1180 } 1181 1182 Message msg; 1183 1184 msg = obtainMessage(); 1185 msg.what = EVENT_POLL_SIGNAL_STRENGTH; 1186 1187 // TODO Don't poll signal strength if screen is off 1188 sendMessageDelayed(msg, POLL_PERIOD_MILLIS); 1189 } 1190 1191 protected int radioTechnologyToDataServiceState(int code) { 1192 int retVal = ServiceState.STATE_OUT_OF_SERVICE; 1193 switch(code) { 1194 case 0: 1195 case 1: 1196 case 2: 1197 case 3: 1198 case 4: 1199 case 5: 1200 break; 1201 case 6: // RADIO_TECHNOLOGY_1xRTT 1202 case 7: // RADIO_TECHNOLOGY_EVDO_0 1203 case 8: // RADIO_TECHNOLOGY_EVDO_A 1204 case 12: // RADIO_TECHNOLOGY_EVDO_B 1205 case 13: // RADIO_TECHNOLOGY_EHRPD 1206 retVal = ServiceState.STATE_IN_SERVICE; 1207 break; 1208 default: 1209 loge("radioTechnologyToDataServiceState: Wrong radioTechnology code."); 1210 break; 1211 } 1212 return(retVal); 1213 } 1214 1215 /** code is registration state 0-5 from TS 27.007 7.2 */ 1216 protected int 1217 regCodeToServiceState(int code) { 1218 switch (code) { 1219 case 0: // Not searching and not registered 1220 return ServiceState.STATE_OUT_OF_SERVICE; 1221 case 1: 1222 return ServiceState.STATE_IN_SERVICE; 1223 case 2: // 2 is "searching", fall through 1224 case 3: // 3 is "registration denied", fall through 1225 case 4: // 4 is "unknown", not valid in current baseband 1226 return ServiceState.STATE_OUT_OF_SERVICE; 1227 case 5:// 5 is "Registered, roaming" 1228 return ServiceState.STATE_IN_SERVICE; 1229 1230 default: 1231 loge("regCodeToServiceState: unexpected service state " + code); 1232 return ServiceState.STATE_OUT_OF_SERVICE; 1233 } 1234 } 1235 1236 @Override 1237 public int getCurrentDataConnectionState() { 1238 return mSS.getDataRegState(); 1239 } 1240 1241 /** 1242 * code is registration state 0-5 from TS 27.007 7.2 1243 * returns true if registered roam, false otherwise 1244 */ 1245 private boolean 1246 regCodeIsRoaming (int code) { 1247 // 5 is "in service -- roam" 1248 return 5 == code; 1249 } 1250 1251 /** 1252 * Determine whether a roaming indicator is in the carrier-specified list of ERIs for 1253 * home system 1254 * 1255 * @param roamInd roaming indicator in String 1256 * @return true if the roamInd is in the carrier-specified list of ERIs for home network 1257 */ 1258 private boolean isRoamIndForHomeSystem(String roamInd) { 1259 // retrieve the carrier-specified list of ERIs for home system 1260 String homeRoamIndicators = SystemProperties.get("ro.cdma.homesystem"); 1261 1262 if (!TextUtils.isEmpty(homeRoamIndicators)) { 1263 // searches through the comma-separated list for a match, 1264 // return true if one is found. 1265 for (String homeRoamInd : homeRoamIndicators.split(",")) { 1266 if (homeRoamInd.equals(roamInd)) { 1267 return true; 1268 } 1269 } 1270 // no matches found against the list! 1271 return false; 1272 } 1273 1274 // no system property found for the roaming indicators for home system 1275 return false; 1276 } 1277 1278 /** 1279 * Set roaming state when cdmaRoaming is true and ons is different from spn 1280 * @param cdmaRoaming TS 27.007 7.2 CREG registered roaming 1281 * @param s ServiceState hold current ons 1282 * @return true for roaming state set 1283 */ 1284 private 1285 boolean isRoamingBetweenOperators(boolean cdmaRoaming, ServiceState s) { 1286 String spn = SystemProperties.get(TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA, "empty"); 1287 1288 // NOTE: in case of RUIM we should completely ignore the ERI data file and 1289 // mOperatorAlphaLong is set from RIL_REQUEST_OPERATOR response 0 (alpha ONS) 1290 String onsl = s.getOperatorAlphaLong(); 1291 String onss = s.getOperatorAlphaShort(); 1292 1293 boolean equalsOnsl = onsl != null && spn.equals(onsl); 1294 boolean equalsOnss = onss != null && spn.equals(onss); 1295 1296 return cdmaRoaming && !(equalsOnsl || equalsOnss); 1297 } 1298 1299 1300 /** 1301 * nitzReceiveTime is time_t that the NITZ time was posted 1302 */ 1303 1304 private 1305 void setTimeFromNITZString (String nitz, long nitzReceiveTime) 1306 { 1307 // "yy/mm/dd,hh:mm:ss(+/-)tz" 1308 // tz is in number of quarter-hours 1309 1310 long start = SystemClock.elapsedRealtime(); 1311 if (DBG) { 1312 log("NITZ: " + nitz + "," + nitzReceiveTime + 1313 " start=" + start + " delay=" + (start - nitzReceiveTime)); 1314 } 1315 1316 try { 1317 /* NITZ time (hour:min:sec) will be in UTC but it supplies the timezone 1318 * offset as well (which we won't worry about until later) */ 1319 Calendar c = Calendar.getInstance(TimeZone.getTimeZone("GMT")); 1320 1321 c.clear(); 1322 c.set(Calendar.DST_OFFSET, 0); 1323 1324 String[] nitzSubs = nitz.split("[/:,+-]"); 1325 1326 int year = 2000 + Integer.parseInt(nitzSubs[0]); 1327 c.set(Calendar.YEAR, year); 1328 1329 // month is 0 based! 1330 int month = Integer.parseInt(nitzSubs[1]) - 1; 1331 c.set(Calendar.MONTH, month); 1332 1333 int date = Integer.parseInt(nitzSubs[2]); 1334 c.set(Calendar.DATE, date); 1335 1336 int hour = Integer.parseInt(nitzSubs[3]); 1337 c.set(Calendar.HOUR, hour); 1338 1339 int minute = Integer.parseInt(nitzSubs[4]); 1340 c.set(Calendar.MINUTE, minute); 1341 1342 int second = Integer.parseInt(nitzSubs[5]); 1343 c.set(Calendar.SECOND, second); 1344 1345 boolean sign = (nitz.indexOf('-') == -1); 1346 1347 int tzOffset = Integer.parseInt(nitzSubs[6]); 1348 1349 int dst = (nitzSubs.length >= 8 ) ? Integer.parseInt(nitzSubs[7]) 1350 : 0; 1351 1352 // The zone offset received from NITZ is for current local time, 1353 // so DST correction is already applied. Don't add it again. 1354 // 1355 // tzOffset += dst * 4; 1356 // 1357 // We could unapply it if we wanted the raw offset. 1358 1359 tzOffset = (sign ? 1 : -1) * tzOffset * 15 * 60 * 1000; 1360 1361 TimeZone zone = null; 1362 1363 // As a special extension, the Android emulator appends the name of 1364 // the host computer's timezone to the nitz string. this is zoneinfo 1365 // timezone name of the form Area!Location or Area!Location!SubLocation 1366 // so we need to convert the ! into / 1367 if (nitzSubs.length >= 9) { 1368 String tzname = nitzSubs[8].replace('!','/'); 1369 zone = TimeZone.getTimeZone( tzname ); 1370 } 1371 1372 String iso = SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY); 1373 1374 if (zone == null) { 1375 if (mGotCountryCode) { 1376 if (iso != null && iso.length() > 0) { 1377 zone = TimeUtils.getTimeZone(tzOffset, dst != 0, 1378 c.getTimeInMillis(), 1379 iso); 1380 } else { 1381 // We don't have a valid iso country code. This is 1382 // most likely because we're on a test network that's 1383 // using a bogus MCC (eg, "001"), so get a TimeZone 1384 // based only on the NITZ parameters. 1385 zone = getNitzTimeZone(tzOffset, (dst != 0), c.getTimeInMillis()); 1386 } 1387 } 1388 } 1389 1390 if ((zone == null) || (mZoneOffset != tzOffset) || (mZoneDst != (dst != 0))){ 1391 // We got the time before the country or the zone has changed 1392 // so we don't know how to identify the DST rules yet. Save 1393 // the information and hope to fix it up later. 1394 1395 mNeedFixZone = true; 1396 mZoneOffset = tzOffset; 1397 mZoneDst = dst != 0; 1398 mZoneTime = c.getTimeInMillis(); 1399 } 1400 if (DBG) { 1401 log("NITZ: tzOffset=" + tzOffset + " dst=" + dst + " zone=" + 1402 (zone!=null ? zone.getID() : "NULL") + 1403 " iso=" + iso + " mGotCountryCode=" + mGotCountryCode + 1404 " mNeedFixZone=" + mNeedFixZone); 1405 } 1406 1407 if (zone != null) { 1408 if (getAutoTimeZone()) { 1409 setAndBroadcastNetworkSetTimeZone(zone.getID()); 1410 } 1411 saveNitzTimeZone(zone.getID()); 1412 } 1413 1414 String ignore = SystemProperties.get("gsm.ignore-nitz"); 1415 if (ignore != null && ignore.equals("yes")) { 1416 if (DBG) log("NITZ: Not setting clock because gsm.ignore-nitz is set"); 1417 return; 1418 } 1419 1420 try { 1421 mWakeLock.acquire(); 1422 1423 /** 1424 * Correct the NITZ time by how long its taken to get here. 1425 */ 1426 long millisSinceNitzReceived 1427 = SystemClock.elapsedRealtime() - nitzReceiveTime; 1428 1429 if (millisSinceNitzReceived < 0) { 1430 // Sanity check: something is wrong 1431 if (DBG) { 1432 log("NITZ: not setting time, clock has rolled " 1433 + "backwards since NITZ time was received, " 1434 + nitz); 1435 } 1436 return; 1437 } 1438 1439 if (millisSinceNitzReceived > Integer.MAX_VALUE) { 1440 // If the time is this far off, something is wrong > 24 days! 1441 if (DBG) { 1442 log("NITZ: not setting time, processing has taken " 1443 + (millisSinceNitzReceived / (1000 * 60 * 60 * 24)) 1444 + " days"); 1445 } 1446 return; 1447 } 1448 1449 // Note: with range checks above, cast to int is safe 1450 c.add(Calendar.MILLISECOND, (int)millisSinceNitzReceived); 1451 1452 if (getAutoTime()) { 1453 /** 1454 * Update system time automatically 1455 */ 1456 long gained = c.getTimeInMillis() - System.currentTimeMillis(); 1457 long timeSinceLastUpdate = SystemClock.elapsedRealtime() - mSavedAtTime; 1458 int nitzUpdateSpacing = Settings.Global.getInt(mCr, 1459 Settings.Global.NITZ_UPDATE_SPACING, mNitzUpdateSpacing); 1460 int nitzUpdateDiff = Settings.Global.getInt(mCr, 1461 Settings.Global.NITZ_UPDATE_DIFF, mNitzUpdateDiff); 1462 1463 if ((mSavedAtTime == 0) || (timeSinceLastUpdate > nitzUpdateSpacing) 1464 || (Math.abs(gained) > nitzUpdateDiff)) { 1465 if (DBG) { 1466 log("NITZ: Auto updating time of day to " + c.getTime() 1467 + " NITZ receive delay=" + millisSinceNitzReceived 1468 + "ms gained=" + gained + "ms from " + nitz); 1469 } 1470 1471 setAndBroadcastNetworkSetTime(c.getTimeInMillis()); 1472 } else { 1473 if (DBG) { 1474 log("NITZ: ignore, a previous update was " 1475 + timeSinceLastUpdate + "ms ago and gained=" + gained + "ms"); 1476 } 1477 return; 1478 } 1479 } 1480 1481 /** 1482 * Update properties and save the time we did the update 1483 */ 1484 if (DBG) log("NITZ: update nitz time property"); 1485 SystemProperties.set("gsm.nitz.time", String.valueOf(c.getTimeInMillis())); 1486 mSavedTime = c.getTimeInMillis(); 1487 mSavedAtTime = SystemClock.elapsedRealtime(); 1488 } finally { 1489 long end = SystemClock.elapsedRealtime(); 1490 if (DBG) log("NITZ: end=" + end + " dur=" + (end - start)); 1491 mWakeLock.release(); 1492 } 1493 } catch (RuntimeException ex) { 1494 loge("NITZ: Parsing NITZ time " + nitz + " ex=" + ex); 1495 } 1496 } 1497 1498 private boolean getAutoTime() { 1499 try { 1500 return Settings.Global.getInt(mCr, Settings.Global.AUTO_TIME) > 0; 1501 } catch (SettingNotFoundException snfe) { 1502 return true; 1503 } 1504 } 1505 1506 private boolean getAutoTimeZone() { 1507 try { 1508 return Settings.Global.getInt(mCr, Settings.Global.AUTO_TIME_ZONE) > 0; 1509 } catch (SettingNotFoundException snfe) { 1510 return true; 1511 } 1512 } 1513 1514 private void saveNitzTimeZone(String zoneId) { 1515 mSavedTimeZone = zoneId; 1516 } 1517 1518 /** 1519 * Set the timezone and send out a sticky broadcast so the system can 1520 * determine if the timezone was set by the carrier. 1521 * 1522 * @param zoneId timezone set by carrier 1523 */ 1524 private void setAndBroadcastNetworkSetTimeZone(String zoneId) { 1525 if (DBG) log("setAndBroadcastNetworkSetTimeZone: setTimeZone=" + zoneId); 1526 AlarmManager alarm = 1527 (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE); 1528 alarm.setTimeZone(zoneId); 1529 Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE); 1530 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); 1531 intent.putExtra("time-zone", zoneId); 1532 mPhone.getContext().sendStickyBroadcastAsUser(intent, UserHandle.ALL); 1533 } 1534 1535 /** 1536 * Set the time and Send out a sticky broadcast so the system can determine 1537 * if the time was set by the carrier. 1538 * 1539 * @param time time set by network 1540 */ 1541 private void setAndBroadcastNetworkSetTime(long time) { 1542 if (DBG) log("setAndBroadcastNetworkSetTime: time=" + time + "ms"); 1543 SystemClock.setCurrentTimeMillis(time); 1544 Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIME); 1545 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); 1546 intent.putExtra("time", time); 1547 mPhone.getContext().sendStickyBroadcastAsUser(intent, UserHandle.ALL); 1548 } 1549 1550 private void revertToNitzTime() { 1551 if (Settings.Global.getInt(mCr, Settings.Global.AUTO_TIME, 0) == 0) { 1552 return; 1553 } 1554 if (DBG) { 1555 log("revertToNitzTime: mSavedTime=" + mSavedTime + " mSavedAtTime=" + mSavedAtTime); 1556 } 1557 if (mSavedTime != 0 && mSavedAtTime != 0) { 1558 setAndBroadcastNetworkSetTime(mSavedTime 1559 + (SystemClock.elapsedRealtime() - mSavedAtTime)); 1560 } 1561 } 1562 1563 private void revertToNitzTimeZone() { 1564 if (Settings.Global.getInt(mPhone.getContext().getContentResolver(), 1565 Settings.Global.AUTO_TIME_ZONE, 0) == 0) { 1566 return; 1567 } 1568 if (DBG) log("revertToNitzTimeZone: tz='" + mSavedTimeZone); 1569 if (mSavedTimeZone != null) { 1570 setAndBroadcastNetworkSetTimeZone(mSavedTimeZone); 1571 } 1572 } 1573 1574 protected boolean isSidsAllZeros() { 1575 if (mHomeSystemId != null) { 1576 for (int i=0; i < mHomeSystemId.length; i++) { 1577 if (mHomeSystemId[i] != 0) { 1578 return false; 1579 } 1580 } 1581 } 1582 return true; 1583 } 1584 1585 /** 1586 * Check whether a specified system ID that matches one of the home system IDs. 1587 */ 1588 private boolean isHomeSid(int sid) { 1589 if (mHomeSystemId != null) { 1590 for (int i=0; i < mHomeSystemId.length; i++) { 1591 if (sid == mHomeSystemId[i]) { 1592 return true; 1593 } 1594 } 1595 } 1596 return false; 1597 } 1598 1599 /** 1600 * @return true if phone is camping on a technology 1601 * that could support voice and data simultaneously. 1602 */ 1603 @Override 1604 public boolean isConcurrentVoiceAndDataAllowed() { 1605 // Note: it needs to be confirmed which CDMA network types 1606 // can support voice and data calls concurrently. 1607 // For the time-being, the return value will be false. 1608 return false; 1609 } 1610 1611 public String getMdnNumber() { 1612 return mMdn; 1613 } 1614 1615 public String getCdmaMin() { 1616 return mMin; 1617 } 1618 1619 /** Returns null if NV is not yet ready */ 1620 public String getPrlVersion() { 1621 return mPrlVersion; 1622 } 1623 1624 /** 1625 * Returns IMSI as MCC + MNC + MIN 1626 */ 1627 String getImsi() { 1628 // TODO: When RUIM is enabled, IMSI will come from RUIM not build-time props. 1629 String operatorNumeric = SystemProperties.get( 1630 TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC, ""); 1631 1632 if (!TextUtils.isEmpty(operatorNumeric) && getCdmaMin() != null) { 1633 return (operatorNumeric + getCdmaMin()); 1634 } else { 1635 return null; 1636 } 1637 } 1638 1639 /** 1640 * Check if subscription data has been assigned to mMin 1641 * 1642 * return true if MIN info is ready; false otherwise. 1643 */ 1644 public boolean isMinInfoReady() { 1645 return mIsMinInfoReady; 1646 } 1647 1648 /** 1649 * Returns OTASP_UNKNOWN, OTASP_NEEDED or OTASP_NOT_NEEDED 1650 */ 1651 int getOtasp() { 1652 int provisioningState; 1653 if (mMin == null || (mMin.length() < 6)) { 1654 if (DBG) log("getOtasp: bad mMin='" + mMin + "'"); 1655 provisioningState = OTASP_UNKNOWN; 1656 } else { 1657 if ((mMin.equals(UNACTIVATED_MIN_VALUE) 1658 || mMin.substring(0,6).equals(UNACTIVATED_MIN2_VALUE)) 1659 || SystemProperties.getBoolean("test_cdma_setup", false)) { 1660 provisioningState = OTASP_NEEDED; 1661 } else { 1662 provisioningState = OTASP_NOT_NEEDED; 1663 } 1664 } 1665 if (DBG) log("getOtasp: state=" + provisioningState); 1666 return provisioningState; 1667 } 1668 1669 @Override 1670 protected void hangupAndPowerOff() { 1671 // hang up all active voice calls 1672 mPhone.mCT.mRingingCall.hangupIfAlive(); 1673 mPhone.mCT.mBackgroundCall.hangupIfAlive(); 1674 mPhone.mCT.mForegroundCall.hangupIfAlive(); 1675 mCi.setRadioPower(false, null); 1676 } 1677 1678 protected void parseSidNid (String sidStr, String nidStr) { 1679 if (sidStr != null) { 1680 String[] sid = sidStr.split(","); 1681 mHomeSystemId = new int[sid.length]; 1682 for (int i = 0; i < sid.length; i++) { 1683 try { 1684 mHomeSystemId[i] = Integer.parseInt(sid[i]); 1685 } catch (NumberFormatException ex) { 1686 loge("error parsing system id: " + ex); 1687 } 1688 } 1689 } 1690 if (DBG) log("CDMA_SUBSCRIPTION: SID=" + sidStr); 1691 1692 if (nidStr != null) { 1693 String[] nid = nidStr.split(","); 1694 mHomeNetworkId = new int[nid.length]; 1695 for (int i = 0; i < nid.length; i++) { 1696 try { 1697 mHomeNetworkId[i] = Integer.parseInt(nid[i]); 1698 } catch (NumberFormatException ex) { 1699 loge("CDMA_SUBSCRIPTION: error parsing network id: " + ex); 1700 } 1701 } 1702 } 1703 if (DBG) log("CDMA_SUBSCRIPTION: NID=" + nidStr); 1704 } 1705 1706 protected void updateOtaspState() { 1707 int otaspMode = getOtasp(); 1708 int oldOtaspMode = mCurrentOtaspMode; 1709 mCurrentOtaspMode = otaspMode; 1710 1711 // Notify apps subscription info is ready 1712 if (mCdmaForSubscriptionInfoReadyRegistrants != null) { 1713 if (DBG) log("CDMA_SUBSCRIPTION: call notifyRegistrants()"); 1714 mCdmaForSubscriptionInfoReadyRegistrants.notifyRegistrants(); 1715 } 1716 if (oldOtaspMode != mCurrentOtaspMode) { 1717 if (DBG) { 1718 log("CDMA_SUBSCRIPTION: call notifyOtaspChanged old otaspMode=" + 1719 oldOtaspMode + " new otaspMode=" + mCurrentOtaspMode); 1720 } 1721 mPhone.notifyOtaspChanged(mCurrentOtaspMode); 1722 } 1723 } 1724 1725 @Override 1726 protected void onUpdateIccAvailability() { 1727 if (mUiccController == null ) { 1728 return; 1729 } 1730 1731 UiccCardApplication newUiccApplication = 1732 mUiccController.getUiccCardApplication(UiccController.APP_FAM_3GPP2); 1733 1734 if (mUiccApplcation != newUiccApplication) { 1735 if (mUiccApplcation != null) { 1736 log("Removing stale icc objects."); 1737 mUiccApplcation.unregisterForReady(this); 1738 if (mIccRecords != null) { 1739 mIccRecords.unregisterForRecordsLoaded(this); 1740 } 1741 mIccRecords = null; 1742 mUiccApplcation = null; 1743 } 1744 if (newUiccApplication != null) { 1745 log("New card found"); 1746 mUiccApplcation = newUiccApplication; 1747 mIccRecords = mUiccApplcation.getIccRecords(); 1748 if (mIsSubscriptionFromRuim) { 1749 mUiccApplcation.registerForReady(this, EVENT_RUIM_READY, null); 1750 if (mIccRecords != null) { 1751 mIccRecords.registerForRecordsLoaded(this, EVENT_RUIM_RECORDS_LOADED, null); 1752 } 1753 } 1754 } 1755 } 1756 } 1757 1758 @Override 1759 protected void log(String s) { 1760 Rlog.d(LOG_TAG, "[CdmaSST] " + s); 1761 } 1762 1763 @Override 1764 protected void loge(String s) { 1765 Rlog.e(LOG_TAG, "[CdmaSST] " + s); 1766 } 1767 1768 @Override 1769 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1770 pw.println("CdmaServiceStateTracker extends:"); 1771 super.dump(fd, pw, args); 1772 pw.println(" mPhone=" + mPhone); 1773 pw.println(" mSS=" + mSS); 1774 pw.println(" mNewSS=" + mNewSS); 1775 pw.println(" mCellLoc=" + mCellLoc); 1776 pw.println(" mNewCellLoc=" + mNewCellLoc); 1777 pw.println(" mCurrentOtaspMode=" + mCurrentOtaspMode); 1778 pw.println(" mCdmaRoaming=" + mCdmaRoaming); 1779 pw.println(" mRoamingIndicator=" + mRoamingIndicator); 1780 pw.println(" mIsInPrl=" + mIsInPrl); 1781 pw.println(" mDefaultRoamingIndicator=" + mDefaultRoamingIndicator); 1782 pw.println(" mRegistrationState=" + mRegistrationState); 1783 pw.println(" mNeedFixZone=" + mNeedFixZone); 1784 pw.println(" mZoneOffset=" + mZoneOffset); 1785 pw.println(" mZoneDst=" + mZoneDst); 1786 pw.println(" mZoneTime=" + mZoneTime); 1787 pw.println(" mGotCountryCode=" + mGotCountryCode); 1788 pw.println(" mSavedTimeZone=" + mSavedTimeZone); 1789 pw.println(" mSavedTime=" + mSavedTime); 1790 pw.println(" mSavedAtTime=" + mSavedAtTime); 1791 pw.println(" mWakeLock=" + mWakeLock); 1792 pw.println(" mCurPlmn=" + mCurPlmn); 1793 pw.println(" mMdn=" + mMdn); 1794 pw.println(" mHomeSystemId=" + mHomeSystemId); 1795 pw.println(" mHomeNetworkId=" + mHomeNetworkId); 1796 pw.println(" mMin=" + mMin); 1797 pw.println(" mPrlVersion=" + mPrlVersion); 1798 pw.println(" mIsMinInfoReady=" + mIsMinInfoReady); 1799 pw.println(" mIsEriTextLoaded=" + mIsEriTextLoaded); 1800 pw.println(" mIsSubscriptionFromRuim=" + mIsSubscriptionFromRuim); 1801 pw.println(" mCdmaSSM=" + mCdmaSSM); 1802 pw.println(" mRegistrationDeniedReason=" + mRegistrationDeniedReason); 1803 pw.println(" mCurrentCarrier=" + mCurrentCarrier); 1804 } 1805 } 1806