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