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