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