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