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