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.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