Home | History | Annotate | Download | only in gsm
      1 /*
      2  * Copyright (C) 2006 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.gsm;
     18 
     19 import android.app.AlarmManager;
     20 import android.app.Notification;
     21 import android.app.NotificationManager;
     22 import android.app.PendingIntent;
     23 import android.content.BroadcastReceiver;
     24 import android.content.ContentResolver;
     25 import android.content.Context;
     26 import android.content.Intent;
     27 import android.content.IntentFilter;
     28 import android.content.res.Resources;
     29 import android.database.ContentObserver;
     30 import android.os.AsyncResult;
     31 import android.os.Build;
     32 import android.os.Handler;
     33 import android.os.Message;
     34 import android.os.PowerManager;
     35 import android.os.SystemClock;
     36 import android.os.SystemProperties;
     37 import android.os.UserHandle;
     38 import android.provider.Settings;
     39 import android.provider.Settings.SettingNotFoundException;
     40 import android.telephony.CellIdentityGsm;
     41 import android.telephony.CellIdentityLte;
     42 import android.telephony.CellIdentityWcdma;
     43 import android.telephony.CellInfo;
     44 import android.telephony.CellInfoGsm;
     45 import android.telephony.CellInfoLte;
     46 import android.telephony.CellInfoWcdma;
     47 import android.telephony.CellLocation;
     48 import android.telephony.Rlog;
     49 import android.telephony.ServiceState;
     50 import android.telephony.SignalStrength;
     51 import android.telephony.gsm.GsmCellLocation;
     52 import android.text.TextUtils;
     53 import android.util.EventLog;
     54 import android.util.TimeUtils;
     55 
     56 import com.android.internal.telephony.CommandException;
     57 import com.android.internal.telephony.CommandsInterface;
     58 import com.android.internal.telephony.EventLogTags;
     59 import com.android.internal.telephony.MccTable;
     60 import com.android.internal.telephony.Phone;
     61 import com.android.internal.telephony.RILConstants;
     62 import com.android.internal.telephony.RestrictedState;
     63 import com.android.internal.telephony.ServiceStateTracker;
     64 import com.android.internal.telephony.TelephonyIntents;
     65 import com.android.internal.telephony.TelephonyProperties;
     66 import com.android.internal.telephony.dataconnection.DcTrackerBase;
     67 import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppState;
     68 import com.android.internal.telephony.uicc.IccRecords;
     69 import com.android.internal.telephony.uicc.SIMRecords;
     70 import com.android.internal.telephony.uicc.UiccCardApplication;
     71 import com.android.internal.telephony.uicc.UiccController;
     72 
     73 import java.io.FileDescriptor;
     74 import java.io.PrintWriter;
     75 import java.util.ArrayList;
     76 import java.util.Arrays;
     77 import java.util.Calendar;
     78 import java.util.Date;
     79 import java.util.List;
     80 import java.util.TimeZone;
     81 
     82 /**
     83  * {@hide}
     84  */
     85 final class GsmServiceStateTracker extends ServiceStateTracker {
     86     private static final String LOG_TAG = "GsmSST";
     87     private static final boolean VDBG = false;
     88 
     89     GSMPhone mPhone;
     90     GsmCellLocation mCellLoc;
     91     GsmCellLocation mNewCellLoc;
     92     int mPreferredNetworkType;
     93 
     94     private int mMaxDataCalls = 1;
     95     private int mNewMaxDataCalls = 1;
     96     private int mReasonDataDenied = -1;
     97     private int mNewReasonDataDenied = -1;
     98 
     99     /**
    100      * GSM roaming status solely based on TS 27.007 7.2 CREG. Only used by
    101      * handlePollStateResult to store CREG roaming result.
    102      */
    103     private boolean mGsmRoaming = false;
    104 
    105     /**
    106      * Data roaming status solely based on TS 27.007 10.1.19 CGREG. Only used by
    107      * handlePollStateResult to store CGREG roaming result.
    108      */
    109     private boolean mDataRoaming = false;
    110 
    111     /**
    112      * Mark when service state is in emergency call only mode
    113      */
    114     private boolean mEmergencyOnly = false;
    115 
    116     /**
    117      * Sometimes we get the NITZ time before we know what country we
    118      * are in. Keep the time zone information from the NITZ string so
    119      * we can fix the time zone once know the country.
    120      */
    121     private boolean mNeedFixZoneAfterNitz = false;
    122     private int mZoneOffset;
    123     private boolean mZoneDst;
    124     private long mZoneTime;
    125     private boolean mGotCountryCode = false;
    126     private ContentResolver mCr;
    127 
    128     /** Boolean is true is setTimeFromNITZString was called */
    129     private boolean mNitzUpdatedTime = false;
    130 
    131     String mSavedTimeZone;
    132     long mSavedTime;
    133     long mSavedAtTime;
    134 
    135     /** Started the recheck process after finding gprs should registered but not. */
    136     private boolean mStartedGprsRegCheck = false;
    137 
    138     /** Already sent the event-log for no gprs register. */
    139     private boolean mReportedGprsNoReg = false;
    140 
    141     /**
    142      * The Notification object given to the NotificationManager.
    143      */
    144     private Notification mNotification;
    145 
    146     /** Wake lock used while setting time of day. */
    147     private PowerManager.WakeLock mWakeLock;
    148     private static final String WAKELOCK_TAG = "ServiceStateTracker";
    149 
    150     /** Keep track of SPN display rules, so we only broadcast intent if something changes. */
    151     private String mCurSpn = null;
    152     private String mCurPlmn = null;
    153     private boolean mCurShowPlmn = false;
    154     private boolean mCurShowSpn = false;
    155 
    156     /** Notification type. */
    157     static final int PS_ENABLED = 1001;            // Access Control blocks data service
    158     static final int PS_DISABLED = 1002;           // Access Control enables data service
    159     static final int CS_ENABLED = 1003;            // Access Control blocks all voice/sms service
    160     static final int CS_DISABLED = 1004;           // Access Control enables all voice/sms service
    161     static final int CS_NORMAL_ENABLED = 1005;     // Access Control blocks normal voice/sms service
    162     static final int CS_EMERGENCY_ENABLED = 1006;  // Access Control blocks emergency call service
    163 
    164     /** Notification id. */
    165     static final int PS_NOTIFICATION = 888;  // Id to update and cancel PS restricted
    166     static final int CS_NOTIFICATION = 999;  // Id to update and cancel CS restricted
    167 
    168     private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
    169         @Override
    170         public void onReceive(Context context, Intent intent) {
    171             if (!mPhone.mIsTheCurrentActivePhone) {
    172                 Rlog.e(LOG_TAG, "Received Intent " + intent +
    173                         " while being destroyed. Ignoring.");
    174                 return;
    175             }
    176 
    177             if (intent.getAction().equals(Intent.ACTION_LOCALE_CHANGED)) {
    178                 // update emergency string whenever locale changed
    179                 updateSpnDisplay();
    180             }
    181         }
    182     };
    183 
    184     private ContentObserver mAutoTimeObserver = new ContentObserver(new Handler()) {
    185         @Override
    186         public void onChange(boolean selfChange) {
    187             Rlog.i("GsmServiceStateTracker", "Auto time state changed");
    188             revertToNitzTime();
    189         }
    190     };
    191 
    192     private ContentObserver mAutoTimeZoneObserver = new ContentObserver(new Handler()) {
    193         @Override
    194         public void onChange(boolean selfChange) {
    195             Rlog.i("GsmServiceStateTracker", "Auto time zone state changed");
    196             revertToNitzTimeZone();
    197         }
    198     };
    199 
    200     public GsmServiceStateTracker(GSMPhone phone) {
    201         super(phone, phone.mCi, new CellInfoGsm());
    202 
    203         mPhone = phone;
    204         mCellLoc = new GsmCellLocation();
    205         mNewCellLoc = new GsmCellLocation();
    206 
    207         PowerManager powerManager =
    208                 (PowerManager)phone.getContext().getSystemService(Context.POWER_SERVICE);
    209         mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG);
    210 
    211         mCi.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);
    212         mCi.registerForRadioStateChanged(this, EVENT_RADIO_STATE_CHANGED, null);
    213 
    214         mCi.registerForVoiceNetworkStateChanged(this, EVENT_NETWORK_STATE_CHANGED, null);
    215         mCi.setOnNITZTime(this, EVENT_NITZ_TIME, null);
    216         mCi.setOnRestrictedStateChanged(this, EVENT_RESTRICTED_STATE_CHANGED, null);
    217 
    218         // system setting property AIRPLANE_MODE_ON is set in Settings.
    219         int airplaneMode = Settings.Global.getInt(
    220                 phone.getContext().getContentResolver(),
    221                 Settings.Global.AIRPLANE_MODE_ON, 0);
    222         mDesiredPowerState = ! (airplaneMode > 0);
    223 
    224         mCr = phone.getContext().getContentResolver();
    225         mCr.registerContentObserver(
    226                 Settings.Global.getUriFor(Settings.Global.AUTO_TIME), true,
    227                 mAutoTimeObserver);
    228         mCr.registerContentObserver(
    229                 Settings.Global.getUriFor(Settings.Global.AUTO_TIME_ZONE), true,
    230                 mAutoTimeZoneObserver);
    231 
    232         setSignalStrengthDefaultValues();
    233 
    234         // Monitor locale change
    235         IntentFilter filter = new IntentFilter();
    236         filter.addAction(Intent.ACTION_LOCALE_CHANGED);
    237         phone.getContext().registerReceiver(mIntentReceiver, filter);
    238 
    239         // Gsm doesn't support OTASP so its not needed
    240         phone.notifyOtaspChanged(OTASP_NOT_NEEDED);
    241     }
    242 
    243     @Override
    244     public void dispose() {
    245         checkCorrectThread();
    246         log("ServiceStateTracker dispose");
    247 
    248         // Unregister for all events.
    249         mCi.unregisterForAvailable(this);
    250         mCi.unregisterForRadioStateChanged(this);
    251         mCi.unregisterForVoiceNetworkStateChanged(this);
    252         if (mUiccApplcation != null) {mUiccApplcation.unregisterForReady(this);}
    253         if (mIccRecords != null) {mIccRecords.unregisterForRecordsLoaded(this);}
    254         mCi.unSetOnRestrictedStateChanged(this);
    255         mCi.unSetOnNITZTime(this);
    256         mCr.unregisterContentObserver(mAutoTimeObserver);
    257         mCr.unregisterContentObserver(mAutoTimeZoneObserver);
    258         mPhone.getContext().unregisterReceiver(mIntentReceiver);
    259         super.dispose();
    260     }
    261 
    262     @Override
    263     protected void finalize() {
    264         if(DBG) log("finalize");
    265     }
    266 
    267     @Override
    268     protected Phone getPhone() {
    269         return mPhone;
    270     }
    271 
    272     @Override
    273     public void handleMessage (Message msg) {
    274         AsyncResult ar;
    275         int[] ints;
    276         String[] strings;
    277         Message message;
    278 
    279         if (!mPhone.mIsTheCurrentActivePhone) {
    280             Rlog.e(LOG_TAG, "Received message " + msg +
    281                     "[" + msg.what + "] while being destroyed. Ignoring.");
    282             return;
    283         }
    284         switch (msg.what) {
    285             case EVENT_RADIO_AVAILABLE:
    286                 //this is unnecessary
    287                 //setPowerStateToDesired();
    288                 break;
    289 
    290             case EVENT_SIM_READY:
    291                 // Set the network type, in case the radio does not restore it.
    292                 mCi.setCurrentPreferredNetworkType();
    293 
    294                 boolean skipRestoringSelection = mPhone.getContext().getResources().getBoolean(
    295                         com.android.internal.R.bool.skip_restoring_network_selection);
    296 
    297                 if (!skipRestoringSelection) {
    298                     // restore the previous network selection.
    299                     mPhone.restoreSavedNetworkSelection(null);
    300                 }
    301                 pollState();
    302                 // Signal strength polling stops when radio is off
    303                 queueNextSignalStrengthPoll();
    304                 break;
    305 
    306             case EVENT_RADIO_STATE_CHANGED:
    307                 // This will do nothing in the radio not
    308                 // available case
    309                 setPowerStateToDesired();
    310                 pollState();
    311                 break;
    312 
    313             case EVENT_NETWORK_STATE_CHANGED:
    314                 pollState();
    315                 break;
    316 
    317             case EVENT_GET_SIGNAL_STRENGTH:
    318                 // This callback is called when signal strength is polled
    319                 // all by itself
    320 
    321                 if (!(mCi.getRadioState().isOn())) {
    322                     // Polling will continue when radio turns back on
    323                     return;
    324                 }
    325                 ar = (AsyncResult) msg.obj;
    326                 onSignalStrengthResult(ar, true);
    327                 queueNextSignalStrengthPoll();
    328 
    329                 break;
    330 
    331             case EVENT_GET_LOC_DONE:
    332                 ar = (AsyncResult) msg.obj;
    333 
    334                 if (ar.exception == null) {
    335                     String states[] = (String[])ar.result;
    336                     int lac = -1;
    337                     int cid = -1;
    338                     if (states.length >= 3) {
    339                         try {
    340                             if (states[1] != null && states[1].length() > 0) {
    341                                 lac = Integer.parseInt(states[1], 16);
    342                             }
    343                             if (states[2] != null && states[2].length() > 0) {
    344                                 cid = Integer.parseInt(states[2], 16);
    345                             }
    346                         } catch (NumberFormatException ex) {
    347                             Rlog.w(LOG_TAG, "error parsing location: " + ex);
    348                         }
    349                     }
    350                     mCellLoc.setLacAndCid(lac, cid);
    351                     mPhone.notifyLocationChanged();
    352                 }
    353 
    354                 // Release any temporary cell lock, which could have been
    355                 // acquired to allow a single-shot location update.
    356                 disableSingleLocationUpdate();
    357                 break;
    358 
    359             case EVENT_POLL_STATE_REGISTRATION:
    360             case EVENT_POLL_STATE_GPRS:
    361             case EVENT_POLL_STATE_OPERATOR:
    362             case EVENT_POLL_STATE_NETWORK_SELECTION_MODE:
    363                 ar = (AsyncResult) msg.obj;
    364 
    365                 handlePollStateResult(msg.what, ar);
    366                 break;
    367 
    368             case EVENT_POLL_SIGNAL_STRENGTH:
    369                 // Just poll signal strength...not part of pollState()
    370 
    371                 mCi.getSignalStrength(obtainMessage(EVENT_GET_SIGNAL_STRENGTH));
    372                 break;
    373 
    374             case EVENT_NITZ_TIME:
    375                 ar = (AsyncResult) msg.obj;
    376 
    377                 String nitzString = (String)((Object[])ar.result)[0];
    378                 long nitzReceiveTime = ((Long)((Object[])ar.result)[1]).longValue();
    379 
    380                 setTimeFromNITZString(nitzString, nitzReceiveTime);
    381                 break;
    382 
    383             case EVENT_SIGNAL_STRENGTH_UPDATE:
    384                 // This is a notification from
    385                 // CommandsInterface.setOnSignalStrengthUpdate
    386 
    387                 ar = (AsyncResult) msg.obj;
    388 
    389                 // The radio is telling us about signal strength changes
    390                 // we don't have to ask it
    391                 mDontPollSignalStrength = true;
    392 
    393                 onSignalStrengthResult(ar, true);
    394                 break;
    395 
    396             case EVENT_SIM_RECORDS_LOADED:
    397                 log("EVENT_SIM_RECORDS_LOADED: what=" + msg.what);
    398 
    399                 updatePhoneObject();
    400                 updateSpnDisplay();
    401                 break;
    402 
    403             case EVENT_LOCATION_UPDATES_ENABLED:
    404                 ar = (AsyncResult) msg.obj;
    405 
    406                 if (ar.exception == null) {
    407                     mCi.getVoiceRegistrationState(obtainMessage(EVENT_GET_LOC_DONE, null));
    408                 }
    409                 break;
    410 
    411             case EVENT_SET_PREFERRED_NETWORK_TYPE:
    412                 ar = (AsyncResult) msg.obj;
    413                 // Don't care the result, only use for dereg network (COPS=2)
    414                 message = obtainMessage(EVENT_RESET_PREFERRED_NETWORK_TYPE, ar.userObj);
    415                 mCi.setPreferredNetworkType(mPreferredNetworkType, message);
    416                 break;
    417 
    418             case EVENT_RESET_PREFERRED_NETWORK_TYPE:
    419                 ar = (AsyncResult) msg.obj;
    420                 if (ar.userObj != null) {
    421                     AsyncResult.forMessage(((Message) ar.userObj)).exception
    422                             = ar.exception;
    423                     ((Message) ar.userObj).sendToTarget();
    424                 }
    425                 break;
    426 
    427             case EVENT_GET_PREFERRED_NETWORK_TYPE:
    428                 ar = (AsyncResult) msg.obj;
    429 
    430                 if (ar.exception == null) {
    431                     mPreferredNetworkType = ((int[])ar.result)[0];
    432                 } else {
    433                     mPreferredNetworkType = RILConstants.NETWORK_MODE_GLOBAL;
    434                 }
    435 
    436                 message = obtainMessage(EVENT_SET_PREFERRED_NETWORK_TYPE, ar.userObj);
    437                 int toggledNetworkType = RILConstants.NETWORK_MODE_GLOBAL;
    438 
    439                 mCi.setPreferredNetworkType(toggledNetworkType, message);
    440                 break;
    441 
    442             case EVENT_CHECK_REPORT_GPRS:
    443                 if (mSS != null && !isGprsConsistent(mSS.getDataRegState(), mSS.getVoiceRegState())) {
    444 
    445                     // Can't register data service while voice service is ok
    446                     // i.e. CREG is ok while CGREG is not
    447                     // possible a network or baseband side error
    448                     GsmCellLocation loc = ((GsmCellLocation)mPhone.getCellLocation());
    449                     EventLog.writeEvent(EventLogTags.DATA_NETWORK_REGISTRATION_FAIL,
    450                             mSS.getOperatorNumeric(), loc != null ? loc.getCid() : -1);
    451                     mReportedGprsNoReg = true;
    452                 }
    453                 mStartedGprsRegCheck = false;
    454                 break;
    455 
    456             case EVENT_RESTRICTED_STATE_CHANGED:
    457                 // This is a notification from
    458                 // CommandsInterface.setOnRestrictedStateChanged
    459 
    460                 if (DBG) log("EVENT_RESTRICTED_STATE_CHANGED");
    461 
    462                 ar = (AsyncResult) msg.obj;
    463 
    464                 onRestrictedStateChanged(ar);
    465                 break;
    466 
    467             default:
    468                 super.handleMessage(msg);
    469             break;
    470         }
    471     }
    472 
    473     @Override
    474     protected void setPowerStateToDesired() {
    475         // If we want it on and it's off, turn it on
    476         if (mDesiredPowerState
    477             && mCi.getRadioState() == CommandsInterface.RadioState.RADIO_OFF) {
    478             mCi.setRadioPower(true, null);
    479         } else if (!mDesiredPowerState && mCi.getRadioState().isOn()) {
    480             // If it's on and available and we want it off gracefully
    481             DcTrackerBase dcTracker = mPhone.mDcTracker;
    482             powerOffRadioSafely(dcTracker);
    483         } // Otherwise, we're in the desired state
    484     }
    485 
    486     @Override
    487     protected void hangupAndPowerOff() {
    488         // hang up all active voice calls
    489         if (mPhone.isInCall()) {
    490             mPhone.mCT.mRingingCall.hangupIfAlive();
    491             mPhone.mCT.mBackgroundCall.hangupIfAlive();
    492             mPhone.mCT.mForegroundCall.hangupIfAlive();
    493         }
    494 
    495         mCi.setRadioPower(false, null);
    496     }
    497 
    498     @Override
    499     protected void updateSpnDisplay() {
    500         // The values of plmn/showPlmn change in different scenarios.
    501         // 1) No service but emergency call allowed -> expected
    502         //    to show "Emergency call only"
    503         //    EXTRA_SHOW_PLMN = true
    504         //    EXTRA_PLMN = "Emergency call only"
    505 
    506         // 2) No service at all --> expected to show "No service"
    507         //    EXTRA_SHOW_PLMN = true
    508         //    EXTRA_PLMN = "No service"
    509 
    510         // 3) Normal operation in either home or roaming service
    511         //    EXTRA_SHOW_PLMN = depending on IccRecords rule
    512         //    EXTRA_PLMN = plmn
    513 
    514         // 4) No service due to power off, aka airplane mode
    515         //    EXTRA_SHOW_PLMN = false
    516         //    EXTRA_PLMN = null
    517 
    518         IccRecords iccRecords = mIccRecords;
    519         String plmn = null;
    520         boolean showPlmn = false;
    521         int rule = (iccRecords != null) ? iccRecords.getDisplayRule(mSS.getOperatorNumeric()) : 0;
    522         if (mSS.getVoiceRegState() == ServiceState.STATE_OUT_OF_SERVICE
    523                 || mSS.getVoiceRegState() == ServiceState.STATE_EMERGENCY_ONLY) {
    524             showPlmn = true;
    525             if (mEmergencyOnly) {
    526                 // No service but emergency call allowed
    527                 plmn = Resources.getSystem().
    528                         getText(com.android.internal.R.string.emergency_calls_only).toString();
    529             } else {
    530                 // No service at all
    531                 plmn = Resources.getSystem().
    532                         getText(com.android.internal.R.string.lockscreen_carrier_default).toString();
    533             }
    534             if (DBG) log("updateSpnDisplay: radio is on but out " +
    535                     "of service, set plmn='" + plmn + "'");
    536         } else if (mSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE) {
    537             // In either home or roaming service
    538             plmn = mSS.getOperatorAlphaLong();
    539             showPlmn = !TextUtils.isEmpty(plmn) &&
    540                     ((rule & SIMRecords.SPN_RULE_SHOW_PLMN)
    541                             == SIMRecords.SPN_RULE_SHOW_PLMN);
    542         } else {
    543             // Power off state, such as airplane mode
    544             if (DBG) log("updateSpnDisplay: radio is off w/ showPlmn="
    545                     + showPlmn + " plmn=" + plmn);
    546         }
    547 
    548         // The value of spn/showSpn are same in different scenarios.
    549         //    EXTRA_SHOW_SPN = depending on IccRecords rule
    550         //    EXTRA_SPN = spn
    551         String spn = (iccRecords != null) ? iccRecords.getServiceProviderName() : "";
    552         boolean showSpn = !TextUtils.isEmpty(spn)
    553                 && ((rule & SIMRecords.SPN_RULE_SHOW_SPN)
    554                         == SIMRecords.SPN_RULE_SHOW_SPN);
    555 
    556         // Update SPN_STRINGS_UPDATED_ACTION IFF any value changes
    557         if (showPlmn != mCurShowPlmn
    558                 || showSpn != mCurShowSpn
    559                 || !TextUtils.equals(spn, mCurSpn)
    560                 || !TextUtils.equals(plmn, mCurPlmn)) {
    561             if (DBG) {
    562                 log(String.format("updateSpnDisplay: changed" +
    563                         " sending intent rule=" + rule +
    564                         " showPlmn='%b' plmn='%s' showSpn='%b' spn='%s'",
    565                         showPlmn, plmn, showSpn, spn));
    566             }
    567             Intent intent = new Intent(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION);
    568             intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
    569             intent.putExtra(TelephonyIntents.EXTRA_SHOW_SPN, showSpn);
    570             intent.putExtra(TelephonyIntents.EXTRA_SPN, spn);
    571             intent.putExtra(TelephonyIntents.EXTRA_SHOW_PLMN, showPlmn);
    572             intent.putExtra(TelephonyIntents.EXTRA_PLMN, plmn);
    573             mPhone.getContext().sendStickyBroadcastAsUser(intent, UserHandle.ALL);
    574         }
    575 
    576         mCurShowSpn = showSpn;
    577         mCurShowPlmn = showPlmn;
    578         mCurSpn = spn;
    579         mCurPlmn = plmn;
    580     }
    581 
    582     /**
    583      * Handle the result of one of the pollState()-related requests
    584      */
    585     @Override
    586     protected void handlePollStateResult (int what, AsyncResult ar) {
    587         int ints[];
    588         String states[];
    589 
    590         // Ignore stale requests from last poll
    591         if (ar.userObj != mPollingContext) return;
    592 
    593         if (ar.exception != null) {
    594             CommandException.Error err=null;
    595 
    596             if (ar.exception instanceof CommandException) {
    597                 err = ((CommandException)(ar.exception)).getCommandError();
    598             }
    599 
    600             if (err == CommandException.Error.RADIO_NOT_AVAILABLE) {
    601                 // Radio has crashed or turned off
    602                 cancelPollState();
    603                 return;
    604             }
    605 
    606             if (!mCi.getRadioState().isOn()) {
    607                 // Radio has crashed or turned off
    608                 cancelPollState();
    609                 return;
    610             }
    611 
    612             if (err != CommandException.Error.OP_NOT_ALLOWED_BEFORE_REG_NW) {
    613                 loge("RIL implementation has returned an error where it must succeed" +
    614                         ar.exception);
    615             }
    616         } else try {
    617             switch (what) {
    618                 case EVENT_POLL_STATE_REGISTRATION: {
    619                     states = (String[])ar.result;
    620                     int lac = -1;
    621                     int cid = -1;
    622                     int type = ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN;
    623                     int regState = ServiceState.RIL_REG_STATE_UNKNOWN;
    624                     int reasonRegStateDenied = -1;
    625                     int psc = -1;
    626                     if (states.length > 0) {
    627                         try {
    628                             regState = Integer.parseInt(states[0]);
    629                             if (states.length >= 3) {
    630                                 if (states[1] != null && states[1].length() > 0) {
    631                                     lac = Integer.parseInt(states[1], 16);
    632                                 }
    633                                 if (states[2] != null && states[2].length() > 0) {
    634                                     cid = Integer.parseInt(states[2], 16);
    635                                 }
    636 
    637                                 // states[3] (if present) is the current radio technology
    638                                 if (states.length >= 4 && states[3] != null) {
    639                                     type = Integer.parseInt(states[3]);
    640                                 }
    641                             }
    642                             if (states.length > 14) {
    643                                 if (states[14] != null && states[14].length() > 0) {
    644                                     psc = Integer.parseInt(states[14], 16);
    645                                 }
    646                             }
    647                         } catch (NumberFormatException ex) {
    648                             loge("error parsing RegistrationState: " + ex);
    649                         }
    650                     }
    651 
    652                     mGsmRoaming = regCodeIsRoaming(regState);
    653                     mNewSS.setState(regCodeToServiceState(regState));
    654                     mNewSS.setRilVoiceRadioTechnology(type);
    655 
    656                     boolean isVoiceCapable = mPhoneBase.getContext().getResources()
    657                             .getBoolean(com.android.internal.R.bool.config_voice_capable);
    658                     if ((regState == ServiceState.RIL_REG_STATE_DENIED_EMERGENCY_CALL_ENABLED
    659                          || regState == ServiceState.RIL_REG_STATE_NOT_REG_EMERGENCY_CALL_ENABLED
    660                          || regState == ServiceState.RIL_REG_STATE_SEARCHING_EMERGENCY_CALL_ENABLED
    661                          || regState == ServiceState.RIL_REG_STATE_UNKNOWN_EMERGENCY_CALL_ENABLED)
    662                          && isVoiceCapable) {
    663                         mEmergencyOnly = true;
    664                     } else {
    665                         mEmergencyOnly = false;
    666                     }
    667 
    668                     // LAC and CID are -1 if not avail
    669                     mNewCellLoc.setLacAndCid(lac, cid);
    670                     mNewCellLoc.setPsc(psc);
    671                     break;
    672                 }
    673 
    674                 case EVENT_POLL_STATE_GPRS: {
    675                     states = (String[])ar.result;
    676 
    677                     int type = 0;
    678                     int regState = ServiceState.RIL_REG_STATE_UNKNOWN;
    679                     mNewReasonDataDenied = -1;
    680                     mNewMaxDataCalls = 1;
    681                     if (states.length > 0) {
    682                         try {
    683                             regState = Integer.parseInt(states[0]);
    684 
    685                             // states[3] (if present) is the current radio technology
    686                             if (states.length >= 4 && states[3] != null) {
    687                                 type = Integer.parseInt(states[3]);
    688                             }
    689                             if ((states.length >= 5 ) &&
    690                                     (regState == ServiceState.RIL_REG_STATE_DENIED)) {
    691                                 mNewReasonDataDenied = Integer.parseInt(states[4]);
    692                             }
    693                             if (states.length >= 6) {
    694                                 mNewMaxDataCalls = Integer.parseInt(states[5]);
    695                             }
    696                         } catch (NumberFormatException ex) {
    697                             loge("error parsing GprsRegistrationState: " + ex);
    698                         }
    699                     }
    700                     int dataRegState = regCodeToServiceState(regState);
    701                     mNewSS.setDataRegState(dataRegState);
    702                     mDataRoaming = regCodeIsRoaming(regState);
    703                     mNewSS.setRilDataRadioTechnology(type);
    704                     if (DBG) {
    705                         log("handlPollStateResultMessage: GsmSST setDataRegState=" + dataRegState
    706                                 + " regState=" + regState
    707                                 + " dataRadioTechnology=" + type);
    708                     }
    709                     break;
    710                 }
    711 
    712                 case EVENT_POLL_STATE_OPERATOR: {
    713                     String opNames[] = (String[])ar.result;
    714 
    715                     if (opNames != null && opNames.length >= 3) {
    716                          mNewSS.setOperatorName (opNames[0], opNames[1], opNames[2]);
    717                     }
    718                     break;
    719                 }
    720 
    721                 case EVENT_POLL_STATE_NETWORK_SELECTION_MODE: {
    722                     ints = (int[])ar.result;
    723                     mNewSS.setIsManualSelection(ints[0] == 1);
    724                     break;
    725                 }
    726             }
    727 
    728         } catch (RuntimeException ex) {
    729             loge("Exception while polling service state. Probably malformed RIL response." + ex);
    730         }
    731 
    732         mPollingContext[0]--;
    733 
    734         if (mPollingContext[0] == 0) {
    735             /**
    736              * Since the roaming state of gsm service (from +CREG) and
    737              * data service (from +CGREG) could be different, the new SS
    738              * is set to roaming when either is true.
    739              *
    740              * There are exceptions for the above rule.
    741              * The new SS is not set as roaming while gsm service reports
    742              * roaming but indeed it is same operator.
    743              * And the operator is considered non roaming.
    744              *
    745              * The test for the operators is to handle special roaming
    746              * agreements and MVNO's.
    747              */
    748             boolean roaming = (mGsmRoaming || mDataRoaming);
    749             if ((mGsmRoaming && isSameNamedOperators(mNewSS)
    750                         && !isSameNamedOperatorConsideredRoaming(mNewSS))
    751                     || isOperatorConsideredNonRoaming(mNewSS)) {
    752                 roaming = false;
    753             }
    754             mNewSS.setRoaming(roaming);
    755             mNewSS.setEmergencyOnly(mEmergencyOnly);
    756             pollStateDone();
    757         }
    758     }
    759 
    760     private void setSignalStrengthDefaultValues() {
    761         mSignalStrength = new SignalStrength(true);
    762     }
    763 
    764     /**
    765      * A complete "service state" from our perspective is
    766      * composed of a handful of separate requests to the radio.
    767      *
    768      * We make all of these requests at once, but then abandon them
    769      * and start over again if the radio notifies us that some
    770      * event has changed
    771      */
    772     private void pollState() {
    773         mPollingContext = new int[1];
    774         mPollingContext[0] = 0;
    775 
    776         switch (mCi.getRadioState()) {
    777             case RADIO_UNAVAILABLE:
    778                 mNewSS.setStateOutOfService();
    779                 mNewCellLoc.setStateInvalid();
    780                 setSignalStrengthDefaultValues();
    781                 mGotCountryCode = false;
    782                 mNitzUpdatedTime = false;
    783                 pollStateDone();
    784             break;
    785 
    786             case RADIO_OFF:
    787                 mNewSS.setStateOff();
    788                 mNewCellLoc.setStateInvalid();
    789                 setSignalStrengthDefaultValues();
    790                 mGotCountryCode = false;
    791                 mNitzUpdatedTime = false;
    792                 pollStateDone();
    793             break;
    794 
    795             default:
    796                 // Issue all poll-related commands at once
    797                 // then count down the responses, which
    798                 // are allowed to arrive out-of-order
    799 
    800                 mPollingContext[0]++;
    801                 mCi.getOperator(
    802                     obtainMessage(
    803                         EVENT_POLL_STATE_OPERATOR, mPollingContext));
    804 
    805                 mPollingContext[0]++;
    806                 mCi.getDataRegistrationState(
    807                     obtainMessage(
    808                         EVENT_POLL_STATE_GPRS, mPollingContext));
    809 
    810                 mPollingContext[0]++;
    811                 mCi.getVoiceRegistrationState(
    812                     obtainMessage(
    813                         EVENT_POLL_STATE_REGISTRATION, mPollingContext));
    814 
    815                 mPollingContext[0]++;
    816                 mCi.getNetworkSelectionMode(
    817                     obtainMessage(
    818                         EVENT_POLL_STATE_NETWORK_SELECTION_MODE, mPollingContext));
    819             break;
    820         }
    821     }
    822 
    823     private void pollStateDone() {
    824         if (DBG) {
    825             log("Poll ServiceState done: " +
    826                 " oldSS=[" + mSS + "] newSS=[" + mNewSS + "]" +
    827                 " oldMaxDataCalls=" + mMaxDataCalls +
    828                 " mNewMaxDataCalls=" + mNewMaxDataCalls +
    829                 " oldReasonDataDenied=" + mReasonDataDenied +
    830                 " mNewReasonDataDenied=" + mNewReasonDataDenied);
    831         }
    832 
    833         if (Build.IS_DEBUGGABLE && SystemProperties.getBoolean(PROP_FORCE_ROAMING, false)) {
    834             mNewSS.setRoaming(true);
    835         }
    836 
    837         useDataRegStateForDataOnlyDevices();
    838 
    839         boolean hasRegistered =
    840             mSS.getVoiceRegState() != ServiceState.STATE_IN_SERVICE
    841             && mNewSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE;
    842 
    843         boolean hasDeregistered =
    844             mSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE
    845             && mNewSS.getVoiceRegState() != ServiceState.STATE_IN_SERVICE;
    846 
    847         boolean hasGprsAttached =
    848                 mSS.getDataRegState() != ServiceState.STATE_IN_SERVICE
    849                 && mNewSS.getDataRegState() == ServiceState.STATE_IN_SERVICE;
    850 
    851         boolean hasGprsDetached =
    852                 mSS.getDataRegState() == ServiceState.STATE_IN_SERVICE
    853                 && mNewSS.getDataRegState() != ServiceState.STATE_IN_SERVICE;
    854 
    855         boolean hasDataRegStateChanged =
    856                 mSS.getDataRegState() != mNewSS.getDataRegState();
    857 
    858         boolean hasVoiceRegStateChanged =
    859                 mSS.getVoiceRegState() != mNewSS.getVoiceRegState();
    860 
    861         boolean hasRilVoiceRadioTechnologyChanged =
    862                 mSS.getRilVoiceRadioTechnology() != mNewSS.getRilVoiceRadioTechnology();
    863 
    864         boolean hasRilDataRadioTechnologyChanged =
    865                 mSS.getRilDataRadioTechnology() != mNewSS.getRilDataRadioTechnology();
    866 
    867         boolean hasChanged = !mNewSS.equals(mSS);
    868 
    869         boolean hasRoamingOn = !mSS.getRoaming() && mNewSS.getRoaming();
    870 
    871         boolean hasRoamingOff = mSS.getRoaming() && !mNewSS.getRoaming();
    872 
    873         boolean hasLocationChanged = !mNewCellLoc.equals(mCellLoc);
    874 
    875         // Add an event log when connection state changes
    876         if (hasVoiceRegStateChanged || hasDataRegStateChanged) {
    877             EventLog.writeEvent(EventLogTags.GSM_SERVICE_STATE_CHANGE,
    878                 mSS.getVoiceRegState(), mSS.getDataRegState(),
    879                 mNewSS.getVoiceRegState(), mNewSS.getDataRegState());
    880         }
    881 
    882         // Add an event log when network type switched
    883         // TODO: we may add filtering to reduce the event logged,
    884         // i.e. check preferred network setting, only switch to 2G, etc
    885         if (hasRilVoiceRadioTechnologyChanged) {
    886             int cid = -1;
    887             GsmCellLocation loc = mNewCellLoc;
    888             if (loc != null) cid = loc.getCid();
    889             // NOTE: this code was previously located after mSS and mNewSS are swapped, so
    890             // existing logs were incorrectly using the new state for "network_from"
    891             // and STATE_OUT_OF_SERVICE for "network_to". To avoid confusion, use a new log tag
    892             // to record the correct states.
    893             EventLog.writeEvent(EventLogTags.GSM_RAT_SWITCHED_NEW, cid,
    894                     mSS.getRilVoiceRadioTechnology(),
    895                     mNewSS.getRilVoiceRadioTechnology());
    896             if (DBG) {
    897                 log("RAT switched "
    898                         + ServiceState.rilRadioTechnologyToString(mSS.getRilVoiceRadioTechnology())
    899                         + " -> "
    900                         + ServiceState.rilRadioTechnologyToString(
    901                                 mNewSS.getRilVoiceRadioTechnology()) + " at cell " + cid);
    902             }
    903         }
    904 
    905         // swap mSS and mNewSS to put new state in mSS
    906         ServiceState tss = mSS;
    907         mSS = mNewSS;
    908         mNewSS = tss;
    909         // clean slate for next time
    910         mNewSS.setStateOutOfService();
    911 
    912         // swap mCellLoc and mNewCellLoc to put new state in mCellLoc
    913         GsmCellLocation tcl = mCellLoc;
    914         mCellLoc = mNewCellLoc;
    915         mNewCellLoc = tcl;
    916 
    917         mReasonDataDenied = mNewReasonDataDenied;
    918         mMaxDataCalls = mNewMaxDataCalls;
    919 
    920         if (hasRilVoiceRadioTechnologyChanged) {
    921             updatePhoneObject();
    922         }
    923 
    924         if (hasRilDataRadioTechnologyChanged) {
    925             mPhone.setSystemProperty(TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE,
    926                     ServiceState.rilRadioTechnologyToString(mSS.getRilVoiceRadioTechnology()));
    927         }
    928 
    929         if (hasRegistered) {
    930             mNetworkAttachedRegistrants.notifyRegistrants();
    931 
    932             if (DBG) {
    933                 log("pollStateDone: registering current mNitzUpdatedTime=" +
    934                         mNitzUpdatedTime + " changing to false");
    935             }
    936             mNitzUpdatedTime = false;
    937         }
    938 
    939         if (hasChanged) {
    940             String operatorNumeric;
    941 
    942             updateSpnDisplay();
    943 
    944             mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ALPHA,
    945                 mSS.getOperatorAlphaLong());
    946 
    947             String prevOperatorNumeric =
    948                     SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_NUMERIC, "");
    949             operatorNumeric = mSS.getOperatorNumeric();
    950             mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_NUMERIC, operatorNumeric);
    951             updateCarrierMccMncConfiguration(operatorNumeric,
    952                     prevOperatorNumeric, mPhone.getContext());
    953             if (operatorNumeric == null) {
    954                 if (DBG) log("operatorNumeric is null");
    955                 mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY, "");
    956                 mGotCountryCode = false;
    957                 mNitzUpdatedTime = false;
    958             } else {
    959                 String iso = "";
    960                 String mcc = "";
    961                 try{
    962                     mcc = operatorNumeric.substring(0, 3);
    963                     iso = MccTable.countryCodeForMcc(Integer.parseInt(mcc));
    964                 } catch ( NumberFormatException ex){
    965                     loge("pollStateDone: countryCodeForMcc error" + ex);
    966                 } catch ( StringIndexOutOfBoundsException ex) {
    967                     loge("pollStateDone: countryCodeForMcc error" + ex);
    968                 }
    969 
    970                 mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY, iso);
    971                 mGotCountryCode = true;
    972 
    973                 TimeZone zone = null;
    974 
    975                 if (!mNitzUpdatedTime && !mcc.equals("000") && !TextUtils.isEmpty(iso) &&
    976                         getAutoTimeZone()) {
    977 
    978                     // Test both paths if ignore nitz is true
    979                     boolean testOneUniqueOffsetPath = SystemProperties.getBoolean(
    980                                 TelephonyProperties.PROPERTY_IGNORE_NITZ, false) &&
    981                                     ((SystemClock.uptimeMillis() & 1) == 0);
    982 
    983                     ArrayList<TimeZone> uniqueZones = TimeUtils.getTimeZonesWithUniqueOffsets(iso);
    984                     if ((uniqueZones.size() == 1) || testOneUniqueOffsetPath) {
    985                         zone = uniqueZones.get(0);
    986                         if (DBG) {
    987                            log("pollStateDone: no nitz but one TZ for iso-cc=" + iso +
    988                                    " with zone.getID=" + zone.getID() +
    989                                    " testOneUniqueOffsetPath=" + testOneUniqueOffsetPath);
    990                         }
    991                         setAndBroadcastNetworkSetTimeZone(zone.getID());
    992                     } else {
    993                         if (DBG) {
    994                             log("pollStateDone: there are " + uniqueZones.size() +
    995                                 " unique offsets for iso-cc='" + iso +
    996                                 " testOneUniqueOffsetPath=" + testOneUniqueOffsetPath +
    997                                 "', do nothing");
    998                         }
    999                     }
   1000                 }
   1001 
   1002                 if (shouldFixTimeZoneNow(mPhone, operatorNumeric, prevOperatorNumeric,
   1003                         mNeedFixZoneAfterNitz)) {
   1004                     // If the offset is (0, false) and the timezone property
   1005                     // is set, use the timezone property rather than
   1006                     // GMT.
   1007                     String zoneName = SystemProperties.get(TIMEZONE_PROPERTY);
   1008                     if (DBG) {
   1009                         log("pollStateDone: fix time zone zoneName='" + zoneName +
   1010                             "' mZoneOffset=" + mZoneOffset + " mZoneDst=" + mZoneDst +
   1011                             " iso-cc='" + iso +
   1012                             "' iso-cc-idx=" + Arrays.binarySearch(GMT_COUNTRY_CODES, iso));
   1013                     }
   1014 
   1015                     // "(mZoneOffset == 0) && (mZoneDst == false) &&
   1016                     //  (Arrays.binarySearch(GMT_COUNTRY_CODES, iso) < 0)"
   1017                     // means that we received a NITZ string telling
   1018                     // it is in GMT+0 w/ DST time zone
   1019                     // BUT iso tells is NOT, e.g, a wrong NITZ reporting
   1020                     // local time w/ 0 offset.
   1021                     if ((mZoneOffset == 0) && (mZoneDst == false) &&
   1022                         (zoneName != null) && (zoneName.length() > 0) &&
   1023                         (Arrays.binarySearch(GMT_COUNTRY_CODES, iso) < 0)) {
   1024                         zone = TimeZone.getDefault();
   1025                         if (mNeedFixZoneAfterNitz) {
   1026                             // For wrong NITZ reporting local time w/ 0 offset,
   1027                             // need adjust time to reflect default timezone setting
   1028                             long ctm = System.currentTimeMillis();
   1029                             long tzOffset = zone.getOffset(ctm);
   1030                             if (DBG) {
   1031                                 log("pollStateDone: tzOffset=" + tzOffset + " ltod=" +
   1032                                         TimeUtils.logTimeOfDay(ctm));
   1033                             }
   1034                             if (getAutoTime()) {
   1035                                 long adj = ctm - tzOffset;
   1036                                 if (DBG) log("pollStateDone: adj ltod=" +
   1037                                         TimeUtils.logTimeOfDay(adj));
   1038                                 setAndBroadcastNetworkSetTime(adj);
   1039                             } else {
   1040                                 // Adjust the saved NITZ time to account for tzOffset.
   1041                                 mSavedTime = mSavedTime - tzOffset;
   1042                             }
   1043                         }
   1044                         if (DBG) log("pollStateDone: using default TimeZone");
   1045                     } else if (iso.equals("")){
   1046                         // Country code not found.  This is likely a test network.
   1047                         // Get a TimeZone based only on the NITZ parameters (best guess).
   1048                         zone = getNitzTimeZone(mZoneOffset, mZoneDst, mZoneTime);
   1049                         if (DBG) log("pollStateDone: using NITZ TimeZone");
   1050                     } else {
   1051                         zone = TimeUtils.getTimeZone(mZoneOffset, mZoneDst, mZoneTime, iso);
   1052                         if (DBG) log("pollStateDone: using getTimeZone(off, dst, time, iso)");
   1053                     }
   1054 
   1055                     mNeedFixZoneAfterNitz = false;
   1056 
   1057                     if (zone != null) {
   1058                         log("pollStateDone: zone != null zone.getID=" + zone.getID());
   1059                         if (getAutoTimeZone()) {
   1060                             setAndBroadcastNetworkSetTimeZone(zone.getID());
   1061                         }
   1062                         saveNitzTimeZone(zone.getID());
   1063                     } else {
   1064                         log("pollStateDone: zone == null");
   1065                     }
   1066                 }
   1067             }
   1068 
   1069             mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISROAMING,
   1070                 mSS.getRoaming() ? "true" : "false");
   1071 
   1072             mPhone.notifyServiceStateChanged(mSS);
   1073         }
   1074 
   1075         if (hasGprsAttached) {
   1076             mAttachedRegistrants.notifyRegistrants();
   1077         }
   1078 
   1079         if (hasGprsDetached) {
   1080             mDetachedRegistrants.notifyRegistrants();
   1081         }
   1082 
   1083         if (hasDataRegStateChanged || hasRilDataRadioTechnologyChanged) {
   1084             notifyDataRegStateRilRadioTechnologyChanged();
   1085             mPhone.notifyDataConnection(null);
   1086         }
   1087 
   1088         if (hasRoamingOn) {
   1089             mRoamingOnRegistrants.notifyRegistrants();
   1090         }
   1091 
   1092         if (hasRoamingOff) {
   1093             mRoamingOffRegistrants.notifyRegistrants();
   1094         }
   1095 
   1096         if (hasLocationChanged) {
   1097             mPhone.notifyLocationChanged();
   1098         }
   1099 
   1100         if (! isGprsConsistent(mSS.getDataRegState(), mSS.getVoiceRegState())) {
   1101             if (!mStartedGprsRegCheck && !mReportedGprsNoReg) {
   1102                 mStartedGprsRegCheck = true;
   1103 
   1104                 int check_period = Settings.Global.getInt(
   1105                         mPhone.getContext().getContentResolver(),
   1106                         Settings.Global.GPRS_REGISTER_CHECK_PERIOD_MS,
   1107                         DEFAULT_GPRS_CHECK_PERIOD_MILLIS);
   1108                 sendMessageDelayed(obtainMessage(EVENT_CHECK_REPORT_GPRS),
   1109                         check_period);
   1110             }
   1111         } else {
   1112             mReportedGprsNoReg = false;
   1113         }
   1114         // TODO: Add GsmCellIdenity updating, see CdmaLteServiceStateTracker.
   1115     }
   1116 
   1117     /**
   1118      * Check if GPRS got registered while voice is registered.
   1119      *
   1120      * @param dataRegState i.e. CGREG in GSM
   1121      * @param voiceRegState i.e. CREG in GSM
   1122      * @return false if device only register to voice but not gprs
   1123      */
   1124     private boolean isGprsConsistent(int dataRegState, int voiceRegState) {
   1125         return !((voiceRegState == ServiceState.STATE_IN_SERVICE) &&
   1126                 (dataRegState != ServiceState.STATE_IN_SERVICE));
   1127     }
   1128 
   1129     /**
   1130      * Returns a TimeZone object based only on parameters from the NITZ string.
   1131      */
   1132     private TimeZone getNitzTimeZone(int offset, boolean dst, long when) {
   1133         TimeZone guess = findTimeZone(offset, dst, when);
   1134         if (guess == null) {
   1135             // Couldn't find a proper timezone.  Perhaps the DST data is wrong.
   1136             guess = findTimeZone(offset, !dst, when);
   1137         }
   1138         if (DBG) log("getNitzTimeZone returning " + (guess == null ? guess : guess.getID()));
   1139         return guess;
   1140     }
   1141 
   1142     private TimeZone findTimeZone(int offset, boolean dst, long when) {
   1143         int rawOffset = offset;
   1144         if (dst) {
   1145             rawOffset -= 3600000;
   1146         }
   1147         String[] zones = TimeZone.getAvailableIDs(rawOffset);
   1148         TimeZone guess = null;
   1149         Date d = new Date(when);
   1150         for (String zone : zones) {
   1151             TimeZone tz = TimeZone.getTimeZone(zone);
   1152             if (tz.getOffset(when) == offset &&
   1153                 tz.inDaylightTime(d) == dst) {
   1154                 guess = tz;
   1155                 break;
   1156             }
   1157         }
   1158 
   1159         return guess;
   1160     }
   1161 
   1162     private void queueNextSignalStrengthPoll() {
   1163         if (mDontPollSignalStrength) {
   1164             // The radio is telling us about signal strength changes
   1165             // we don't have to ask it
   1166             return;
   1167         }
   1168 
   1169         Message msg;
   1170 
   1171         msg = obtainMessage();
   1172         msg.what = EVENT_POLL_SIGNAL_STRENGTH;
   1173 
   1174         long nextTime;
   1175 
   1176         // TODO Don't poll signal strength if screen is off
   1177         sendMessageDelayed(msg, POLL_PERIOD_MILLIS);
   1178     }
   1179 
   1180     /**
   1181      * Set restricted state based on the OnRestrictedStateChanged notification
   1182      * If any voice or packet restricted state changes, trigger a UI
   1183      * notification and notify registrants when sim is ready.
   1184      *
   1185      * @param ar an int value of RIL_RESTRICTED_STATE_*
   1186      */
   1187     private void onRestrictedStateChanged(AsyncResult ar) {
   1188         RestrictedState newRs = new RestrictedState();
   1189 
   1190         if (DBG) log("onRestrictedStateChanged: E rs "+ mRestrictedState);
   1191 
   1192         if (ar.exception == null) {
   1193             int[] ints = (int[])ar.result;
   1194             int state = ints[0];
   1195 
   1196             newRs.setCsEmergencyRestricted(
   1197                     ((state & RILConstants.RIL_RESTRICTED_STATE_CS_EMERGENCY) != 0) ||
   1198                     ((state & RILConstants.RIL_RESTRICTED_STATE_CS_ALL) != 0) );
   1199             //ignore the normal call and data restricted state before SIM READY
   1200             if (mUiccApplcation != null && mUiccApplcation.getState() == AppState.APPSTATE_READY) {
   1201                 newRs.setCsNormalRestricted(
   1202                         ((state & RILConstants.RIL_RESTRICTED_STATE_CS_NORMAL) != 0) ||
   1203                         ((state & RILConstants.RIL_RESTRICTED_STATE_CS_ALL) != 0) );
   1204                 newRs.setPsRestricted(
   1205                         (state & RILConstants.RIL_RESTRICTED_STATE_PS_ALL)!= 0);
   1206             }
   1207 
   1208             if (DBG) log("onRestrictedStateChanged: new rs "+ newRs);
   1209 
   1210             if (!mRestrictedState.isPsRestricted() && newRs.isPsRestricted()) {
   1211                 mPsRestrictEnabledRegistrants.notifyRegistrants();
   1212                 setNotification(PS_ENABLED);
   1213             } else if (mRestrictedState.isPsRestricted() && !newRs.isPsRestricted()) {
   1214                 mPsRestrictDisabledRegistrants.notifyRegistrants();
   1215                 setNotification(PS_DISABLED);
   1216             }
   1217 
   1218             /**
   1219              * There are two kind of cs restriction, normal and emergency. So
   1220              * there are 4 x 4 combinations in current and new restricted states
   1221              * and we only need to notify when state is changed.
   1222              */
   1223             if (mRestrictedState.isCsRestricted()) {
   1224                 if (!newRs.isCsRestricted()) {
   1225                     // remove all restriction
   1226                     setNotification(CS_DISABLED);
   1227                 } else if (!newRs.isCsNormalRestricted()) {
   1228                     // remove normal restriction
   1229                     setNotification(CS_EMERGENCY_ENABLED);
   1230                 } else if (!newRs.isCsEmergencyRestricted()) {
   1231                     // remove emergency restriction
   1232                     setNotification(CS_NORMAL_ENABLED);
   1233                 }
   1234             } else if (mRestrictedState.isCsEmergencyRestricted() &&
   1235                     !mRestrictedState.isCsNormalRestricted()) {
   1236                 if (!newRs.isCsRestricted()) {
   1237                     // remove all restriction
   1238                     setNotification(CS_DISABLED);
   1239                 } else if (newRs.isCsRestricted()) {
   1240                     // enable all restriction
   1241                     setNotification(CS_ENABLED);
   1242                 } else if (newRs.isCsNormalRestricted()) {
   1243                     // remove emergency restriction and enable normal restriction
   1244                     setNotification(CS_NORMAL_ENABLED);
   1245                 }
   1246             } else if (!mRestrictedState.isCsEmergencyRestricted() &&
   1247                     mRestrictedState.isCsNormalRestricted()) {
   1248                 if (!newRs.isCsRestricted()) {
   1249                     // remove all restriction
   1250                     setNotification(CS_DISABLED);
   1251                 } else if (newRs.isCsRestricted()) {
   1252                     // enable all restriction
   1253                     setNotification(CS_ENABLED);
   1254                 } else if (newRs.isCsEmergencyRestricted()) {
   1255                     // remove normal restriction and enable emergency restriction
   1256                     setNotification(CS_EMERGENCY_ENABLED);
   1257                 }
   1258             } else {
   1259                 if (newRs.isCsRestricted()) {
   1260                     // enable all restriction
   1261                     setNotification(CS_ENABLED);
   1262                 } else if (newRs.isCsEmergencyRestricted()) {
   1263                     // enable emergency restriction
   1264                     setNotification(CS_EMERGENCY_ENABLED);
   1265                 } else if (newRs.isCsNormalRestricted()) {
   1266                     // enable normal restriction
   1267                     setNotification(CS_NORMAL_ENABLED);
   1268                 }
   1269             }
   1270 
   1271             mRestrictedState = newRs;
   1272         }
   1273         log("onRestrictedStateChanged: X rs "+ mRestrictedState);
   1274     }
   1275 
   1276     /** code is registration state 0-5 from TS 27.007 7.2 */
   1277     private int regCodeToServiceState(int code) {
   1278         switch (code) {
   1279             case 0:
   1280             case 2: // 2 is "searching"
   1281             case 3: // 3 is "registration denied"
   1282             case 4: // 4 is "unknown" no vaild in current baseband
   1283             case 10:// same as 0, but indicates that emergency call is possible.
   1284             case 12:// same as 2, but indicates that emergency call is possible.
   1285             case 13:// same as 3, but indicates that emergency call is possible.
   1286             case 14:// same as 4, but indicates that emergency call is possible.
   1287                 return ServiceState.STATE_OUT_OF_SERVICE;
   1288 
   1289             case 1:
   1290                 return ServiceState.STATE_IN_SERVICE;
   1291 
   1292             case 5:
   1293                 // in service, roam
   1294                 return ServiceState.STATE_IN_SERVICE;
   1295 
   1296             default:
   1297                 loge("regCodeToServiceState: unexpected service state " + code);
   1298                 return ServiceState.STATE_OUT_OF_SERVICE;
   1299         }
   1300     }
   1301 
   1302 
   1303     /**
   1304      * code is registration state 0-5 from TS 27.007 7.2
   1305      * returns true if registered roam, false otherwise
   1306      */
   1307     private boolean regCodeIsRoaming (int code) {
   1308         return ServiceState.RIL_REG_STATE_ROAMING == code;
   1309     }
   1310 
   1311     /**
   1312      * Set roaming state if operator mcc is the same as sim mcc
   1313      * and ons is different from spn
   1314      *
   1315      * @param s ServiceState hold current ons
   1316      * @return true if same operator
   1317      */
   1318     private boolean isSameNamedOperators(ServiceState s) {
   1319         String spn = SystemProperties.get(TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA, "empty");
   1320 
   1321         String onsl = s.getOperatorAlphaLong();
   1322         String onss = s.getOperatorAlphaShort();
   1323 
   1324         boolean equalsOnsl = onsl != null && spn.equals(onsl);
   1325         boolean equalsOnss = onss != null && spn.equals(onss);
   1326 
   1327         return currentMccEqualsSimMcc(s) && (equalsOnsl || equalsOnss);
   1328     }
   1329 
   1330     /**
   1331      * Compare SIM MCC with Operator MCC
   1332      *
   1333      * @param s ServiceState hold current ons
   1334      * @return true if both are same
   1335      */
   1336     private boolean currentMccEqualsSimMcc(ServiceState s) {
   1337         String simNumeric = SystemProperties.get(
   1338                 TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC, "");
   1339         String operatorNumeric = s.getOperatorNumeric();
   1340         boolean equalsMcc = true;
   1341 
   1342         try {
   1343             equalsMcc = simNumeric.substring(0, 3).
   1344                     equals(operatorNumeric.substring(0, 3));
   1345         } catch (Exception e){
   1346         }
   1347         return equalsMcc;
   1348     }
   1349 
   1350     /**
   1351      * Do not set roaming state in case of oprators considered non-roaming.
   1352      *
   1353      + Can use mcc or mcc+mnc as item of config_operatorConsideredNonRoaming.
   1354      * For example, 302 or 21407. If mcc or mcc+mnc match with operator,
   1355      * don't set roaming state.
   1356      *
   1357      * @param s ServiceState hold current ons
   1358      * @return false for roaming state set
   1359      */
   1360     private boolean isOperatorConsideredNonRoaming(ServiceState s) {
   1361         String operatorNumeric = s.getOperatorNumeric();
   1362         String[] numericArray = mPhone.getContext().getResources().getStringArray(
   1363                     com.android.internal.R.array.config_operatorConsideredNonRoaming);
   1364 
   1365         if (numericArray.length == 0 || operatorNumeric == null) {
   1366             return false;
   1367         }
   1368 
   1369         for (String numeric : numericArray) {
   1370             if (operatorNumeric.startsWith(numeric)) {
   1371                 return true;
   1372             }
   1373         }
   1374         return false;
   1375     }
   1376 
   1377     private boolean isSameNamedOperatorConsideredRoaming(ServiceState s) {
   1378         String operatorNumeric = s.getOperatorNumeric();
   1379         String[] numericArray = mPhone.getContext().getResources().getStringArray(
   1380                     com.android.internal.R.array.config_sameNamedOperatorConsideredRoaming);
   1381 
   1382         if (numericArray.length == 0 || operatorNumeric == null) {
   1383             return false;
   1384         }
   1385 
   1386         for (String numeric : numericArray) {
   1387             if (operatorNumeric.startsWith(numeric)) {
   1388                 return true;
   1389             }
   1390         }
   1391         return false;
   1392     }
   1393 
   1394     /**
   1395      * @return The current GPRS state. IN_SERVICE is the same as "attached"
   1396      * and OUT_OF_SERVICE is the same as detached.
   1397      */
   1398     @Override
   1399     public int getCurrentDataConnectionState() {
   1400         return mSS.getDataRegState();
   1401     }
   1402 
   1403     /**
   1404      * @return true if phone is camping on a technology (eg UMTS)
   1405      * that could support voice and data simultaneously.
   1406      */
   1407     @Override
   1408     public boolean isConcurrentVoiceAndDataAllowed() {
   1409         return (mSS.getRilVoiceRadioTechnology() >= ServiceState.RIL_RADIO_TECHNOLOGY_UMTS);
   1410     }
   1411 
   1412     /**
   1413      * @return the current cell location information. Prefer Gsm location
   1414      * information if available otherwise return LTE location information
   1415      */
   1416     public CellLocation getCellLocation() {
   1417         if ((mCellLoc.getLac() >= 0) && (mCellLoc.getCid() >= 0)) {
   1418             if (DBG) log("getCellLocation(): X good mCellLoc=" + mCellLoc);
   1419             return mCellLoc;
   1420         } else {
   1421             List<CellInfo> result = getAllCellInfo();
   1422             if (result != null) {
   1423                 // A hack to allow tunneling of LTE information via GsmCellLocation
   1424                 // so that older Network Location Providers can return some information
   1425                 // on LTE only networks, see bug 9228974.
   1426                 //
   1427                 // We'll search the return CellInfo array preferring GSM/WCDMA
   1428                 // data, but if there is none we'll tunnel the first LTE information
   1429                 // in the list.
   1430                 //
   1431                 // The tunnel'd LTE information is returned as follows:
   1432                 //   LAC = TAC field
   1433                 //   CID = CI field
   1434                 //   PSC = 0.
   1435                 GsmCellLocation cellLocOther = new GsmCellLocation();
   1436                 for (CellInfo ci : result) {
   1437                     if (ci instanceof CellInfoGsm) {
   1438                         CellInfoGsm cellInfoGsm = (CellInfoGsm)ci;
   1439                         CellIdentityGsm cellIdentityGsm = cellInfoGsm.getCellIdentity();
   1440                         cellLocOther.setLacAndCid(cellIdentityGsm.getLac(),
   1441                                 cellIdentityGsm.getCid());
   1442                         cellLocOther.setPsc(cellIdentityGsm.getPsc());
   1443                         if (DBG) log("getCellLocation(): X ret GSM info=" + cellLocOther);
   1444                         return cellLocOther;
   1445                     } else if (ci instanceof CellInfoWcdma) {
   1446                         CellInfoWcdma cellInfoWcdma = (CellInfoWcdma)ci;
   1447                         CellIdentityWcdma cellIdentityWcdma = cellInfoWcdma.getCellIdentity();
   1448                         cellLocOther.setLacAndCid(cellIdentityWcdma.getLac(),
   1449                                 cellIdentityWcdma.getCid());
   1450                         cellLocOther.setPsc(cellIdentityWcdma.getPsc());
   1451                         if (DBG) log("getCellLocation(): X ret WCDMA info=" + cellLocOther);
   1452                         return cellLocOther;
   1453                     } else if ((ci instanceof CellInfoLte) &&
   1454                             ((cellLocOther.getLac() < 0) || (cellLocOther.getCid() < 0))) {
   1455                         // We'll return the first good LTE info we get if there is no better answer
   1456                         CellInfoLte cellInfoLte = (CellInfoLte)ci;
   1457                         CellIdentityLte cellIdentityLte = cellInfoLte.getCellIdentity();
   1458                         if ((cellIdentityLte.getTac() != Integer.MAX_VALUE)
   1459                                 && (cellIdentityLte.getCi() != Integer.MAX_VALUE)) {
   1460                             cellLocOther.setLacAndCid(cellIdentityLte.getTac(),
   1461                                     cellIdentityLte.getCi());
   1462                             cellLocOther.setPsc(0);
   1463                             if (DBG) {
   1464                                 log("getCellLocation(): possible LTE cellLocOther=" + cellLocOther);
   1465                             }
   1466                         }
   1467                     }
   1468                 }
   1469                 if (DBG) {
   1470                     log("getCellLocation(): X ret best answer cellLocOther=" + cellLocOther);
   1471                 }
   1472                 return cellLocOther;
   1473             } else {
   1474                 if (DBG) {
   1475                     log("getCellLocation(): X empty mCellLoc and CellInfo mCellLoc=" + mCellLoc);
   1476                 }
   1477                 return mCellLoc;
   1478             }
   1479         }
   1480     }
   1481 
   1482     /**
   1483      * nitzReceiveTime is time_t that the NITZ time was posted
   1484      */
   1485     private void setTimeFromNITZString (String nitz, long nitzReceiveTime) {
   1486         // "yy/mm/dd,hh:mm:ss(+/-)tz"
   1487         // tz is in number of quarter-hours
   1488 
   1489         long start = SystemClock.elapsedRealtime();
   1490         if (DBG) {log("NITZ: " + nitz + "," + nitzReceiveTime +
   1491                         " start=" + start + " delay=" + (start - nitzReceiveTime));
   1492         }
   1493 
   1494         try {
   1495             /* NITZ time (hour:min:sec) will be in UTC but it supplies the timezone
   1496              * offset as well (which we won't worry about until later) */
   1497             Calendar c = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
   1498 
   1499             c.clear();
   1500             c.set(Calendar.DST_OFFSET, 0);
   1501 
   1502             String[] nitzSubs = nitz.split("[/:,+-]");
   1503 
   1504             int year = 2000 + Integer.parseInt(nitzSubs[0]);
   1505             c.set(Calendar.YEAR, year);
   1506 
   1507             // month is 0 based!
   1508             int month = Integer.parseInt(nitzSubs[1]) - 1;
   1509             c.set(Calendar.MONTH, month);
   1510 
   1511             int date = Integer.parseInt(nitzSubs[2]);
   1512             c.set(Calendar.DATE, date);
   1513 
   1514             int hour = Integer.parseInt(nitzSubs[3]);
   1515             c.set(Calendar.HOUR, hour);
   1516 
   1517             int minute = Integer.parseInt(nitzSubs[4]);
   1518             c.set(Calendar.MINUTE, minute);
   1519 
   1520             int second = Integer.parseInt(nitzSubs[5]);
   1521             c.set(Calendar.SECOND, second);
   1522 
   1523             boolean sign = (nitz.indexOf('-') == -1);
   1524 
   1525             int tzOffset = Integer.parseInt(nitzSubs[6]);
   1526 
   1527             int dst = (nitzSubs.length >= 8 ) ? Integer.parseInt(nitzSubs[7])
   1528                                               : 0;
   1529 
   1530             // The zone offset received from NITZ is for current local time,
   1531             // so DST correction is already applied.  Don't add it again.
   1532             //
   1533             // tzOffset += dst * 4;
   1534             //
   1535             // We could unapply it if we wanted the raw offset.
   1536 
   1537             tzOffset = (sign ? 1 : -1) * tzOffset * 15 * 60 * 1000;
   1538 
   1539             TimeZone    zone = null;
   1540 
   1541             // As a special extension, the Android emulator appends the name of
   1542             // the host computer's timezone to the nitz string. this is zoneinfo
   1543             // timezone name of the form Area!Location or Area!Location!SubLocation
   1544             // so we need to convert the ! into /
   1545             if (nitzSubs.length >= 9) {
   1546                 String  tzname = nitzSubs[8].replace('!','/');
   1547                 zone = TimeZone.getTimeZone( tzname );
   1548             }
   1549 
   1550             String iso = SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY);
   1551 
   1552             if (zone == null) {
   1553 
   1554                 if (mGotCountryCode) {
   1555                     if (iso != null && iso.length() > 0) {
   1556                         zone = TimeUtils.getTimeZone(tzOffset, dst != 0,
   1557                                 c.getTimeInMillis(),
   1558                                 iso);
   1559                     } else {
   1560                         // We don't have a valid iso country code.  This is
   1561                         // most likely because we're on a test network that's
   1562                         // using a bogus MCC (eg, "001"), so get a TimeZone
   1563                         // based only on the NITZ parameters.
   1564                         zone = getNitzTimeZone(tzOffset, (dst != 0), c.getTimeInMillis());
   1565                     }
   1566                 }
   1567             }
   1568 
   1569             if ((zone == null) || (mZoneOffset != tzOffset) || (mZoneDst != (dst != 0))){
   1570                 // We got the time before the country or the zone has changed
   1571                 // so we don't know how to identify the DST rules yet.  Save
   1572                 // the information and hope to fix it up later.
   1573 
   1574                 mNeedFixZoneAfterNitz = true;
   1575                 mZoneOffset  = tzOffset;
   1576                 mZoneDst     = dst != 0;
   1577                 mZoneTime    = c.getTimeInMillis();
   1578             }
   1579 
   1580             if (zone != null) {
   1581                 if (getAutoTimeZone()) {
   1582                     setAndBroadcastNetworkSetTimeZone(zone.getID());
   1583                 }
   1584                 saveNitzTimeZone(zone.getID());
   1585             }
   1586 
   1587             String ignore = SystemProperties.get("gsm.ignore-nitz");
   1588             if (ignore != null && ignore.equals("yes")) {
   1589                 log("NITZ: Not setting clock because gsm.ignore-nitz is set");
   1590                 return;
   1591             }
   1592 
   1593             try {
   1594                 mWakeLock.acquire();
   1595 
   1596                 if (getAutoTime()) {
   1597                     long millisSinceNitzReceived
   1598                             = SystemClock.elapsedRealtime() - nitzReceiveTime;
   1599 
   1600                     if (millisSinceNitzReceived < 0) {
   1601                         // Sanity check: something is wrong
   1602                         if (DBG) {
   1603                             log("NITZ: not setting time, clock has rolled "
   1604                                             + "backwards since NITZ time was received, "
   1605                                             + nitz);
   1606                         }
   1607                         return;
   1608                     }
   1609 
   1610                     if (millisSinceNitzReceived > Integer.MAX_VALUE) {
   1611                         // If the time is this far off, something is wrong > 24 days!
   1612                         if (DBG) {
   1613                             log("NITZ: not setting time, processing has taken "
   1614                                         + (millisSinceNitzReceived / (1000 * 60 * 60 * 24))
   1615                                         + " days");
   1616                         }
   1617                         return;
   1618                     }
   1619 
   1620                     // Note: with range checks above, cast to int is safe
   1621                     c.add(Calendar.MILLISECOND, (int)millisSinceNitzReceived);
   1622 
   1623                     if (DBG) {
   1624                         log("NITZ: Setting time of day to " + c.getTime()
   1625                             + " NITZ receive delay(ms): " + millisSinceNitzReceived
   1626                             + " gained(ms): "
   1627                             + (c.getTimeInMillis() - System.currentTimeMillis())
   1628                             + " from " + nitz);
   1629                     }
   1630 
   1631                     setAndBroadcastNetworkSetTime(c.getTimeInMillis());
   1632                     Rlog.i(LOG_TAG, "NITZ: after Setting time of day");
   1633                 }
   1634                 SystemProperties.set("gsm.nitz.time", String.valueOf(c.getTimeInMillis()));
   1635                 saveNitzTime(c.getTimeInMillis());
   1636                 if (VDBG) {
   1637                     long end = SystemClock.elapsedRealtime();
   1638                     log("NITZ: end=" + end + " dur=" + (end - start));
   1639                 }
   1640                 mNitzUpdatedTime = true;
   1641             } finally {
   1642                 mWakeLock.release();
   1643             }
   1644         } catch (RuntimeException ex) {
   1645             loge("NITZ: Parsing NITZ time " + nitz + " ex=" + ex);
   1646         }
   1647     }
   1648 
   1649     private boolean getAutoTime() {
   1650         try {
   1651             return Settings.Global.getInt(mPhone.getContext().getContentResolver(),
   1652                     Settings.Global.AUTO_TIME) > 0;
   1653         } catch (SettingNotFoundException snfe) {
   1654             return true;
   1655         }
   1656     }
   1657 
   1658     private boolean getAutoTimeZone() {
   1659         try {
   1660             return Settings.Global.getInt(mPhone.getContext().getContentResolver(),
   1661                     Settings.Global.AUTO_TIME_ZONE) > 0;
   1662         } catch (SettingNotFoundException snfe) {
   1663             return true;
   1664         }
   1665     }
   1666 
   1667     private void saveNitzTimeZone(String zoneId) {
   1668         mSavedTimeZone = zoneId;
   1669     }
   1670 
   1671     private void saveNitzTime(long time) {
   1672         mSavedTime = time;
   1673         mSavedAtTime = SystemClock.elapsedRealtime();
   1674     }
   1675 
   1676     /**
   1677      * Set the timezone and send out a sticky broadcast so the system can
   1678      * determine if the timezone was set by the carrier.
   1679      *
   1680      * @param zoneId timezone set by carrier
   1681      */
   1682     private void setAndBroadcastNetworkSetTimeZone(String zoneId) {
   1683         if (DBG) log("setAndBroadcastNetworkSetTimeZone: setTimeZone=" + zoneId);
   1684         AlarmManager alarm =
   1685             (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE);
   1686         alarm.setTimeZone(zoneId);
   1687         Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE);
   1688         intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
   1689         intent.putExtra("time-zone", zoneId);
   1690         mPhone.getContext().sendStickyBroadcastAsUser(intent, UserHandle.ALL);
   1691         if (DBG) {
   1692             log("setAndBroadcastNetworkSetTimeZone: call alarm.setTimeZone and broadcast zoneId=" +
   1693                 zoneId);
   1694         }
   1695     }
   1696 
   1697     /**
   1698      * Set the time and Send out a sticky broadcast so the system can determine
   1699      * if the time was set by the carrier.
   1700      *
   1701      * @param time time set by network
   1702      */
   1703     private void setAndBroadcastNetworkSetTime(long time) {
   1704         if (DBG) log("setAndBroadcastNetworkSetTime: time=" + time + "ms");
   1705         SystemClock.setCurrentTimeMillis(time);
   1706         Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIME);
   1707         intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
   1708         intent.putExtra("time", time);
   1709         mPhone.getContext().sendStickyBroadcastAsUser(intent, UserHandle.ALL);
   1710     }
   1711 
   1712     private void revertToNitzTime() {
   1713         if (Settings.Global.getInt(mPhone.getContext().getContentResolver(),
   1714                 Settings.Global.AUTO_TIME, 0) == 0) {
   1715             return;
   1716         }
   1717         if (DBG) {
   1718             log("Reverting to NITZ Time: mSavedTime=" + mSavedTime
   1719                 + " mSavedAtTime=" + mSavedAtTime);
   1720         }
   1721         if (mSavedTime != 0 && mSavedAtTime != 0) {
   1722             setAndBroadcastNetworkSetTime(mSavedTime
   1723                     + (SystemClock.elapsedRealtime() - mSavedAtTime));
   1724         }
   1725     }
   1726 
   1727     private void revertToNitzTimeZone() {
   1728         if (Settings.Global.getInt(mPhone.getContext().getContentResolver(),
   1729                 Settings.Global.AUTO_TIME_ZONE, 0) == 0) {
   1730             return;
   1731         }
   1732         if (DBG) log("Reverting to NITZ TimeZone: tz='" + mSavedTimeZone);
   1733         if (mSavedTimeZone != null) {
   1734             setAndBroadcastNetworkSetTimeZone(mSavedTimeZone);
   1735         }
   1736     }
   1737 
   1738     /**
   1739      * Post a notification to NotificationManager for restricted state
   1740      *
   1741      * @param notifyType is one state of PS/CS_*_ENABLE/DISABLE
   1742      */
   1743     private void setNotification(int notifyType) {
   1744 
   1745         if (DBG) log("setNotification: create notification " + notifyType);
   1746         Context context = mPhone.getContext();
   1747 
   1748         mNotification = new Notification();
   1749         mNotification.when = System.currentTimeMillis();
   1750         mNotification.flags = Notification.FLAG_AUTO_CANCEL;
   1751         mNotification.icon = com.android.internal.R.drawable.stat_sys_warning;
   1752         Intent intent = new Intent();
   1753         mNotification.contentIntent = PendingIntent
   1754         .getActivity(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
   1755 
   1756         CharSequence details = "";
   1757         CharSequence title = context.getText(com.android.internal.R.string.RestrictedChangedTitle);
   1758         int notificationId = CS_NOTIFICATION;
   1759 
   1760         switch (notifyType) {
   1761         case PS_ENABLED:
   1762             notificationId = PS_NOTIFICATION;
   1763             details = context.getText(com.android.internal.R.string.RestrictedOnData);
   1764             break;
   1765         case PS_DISABLED:
   1766             notificationId = PS_NOTIFICATION;
   1767             break;
   1768         case CS_ENABLED:
   1769             details = context.getText(com.android.internal.R.string.RestrictedOnAllVoice);
   1770             break;
   1771         case CS_NORMAL_ENABLED:
   1772             details = context.getText(com.android.internal.R.string.RestrictedOnNormal);
   1773             break;
   1774         case CS_EMERGENCY_ENABLED:
   1775             details = context.getText(com.android.internal.R.string.RestrictedOnEmergency);
   1776             break;
   1777         case CS_DISABLED:
   1778             // do nothing and cancel the notification later
   1779             break;
   1780         }
   1781 
   1782         if (DBG) log("setNotification: put notification " + title + " / " +details);
   1783         mNotification.tickerText = title;
   1784         mNotification.setLatestEventInfo(context, title, details,
   1785                 mNotification.contentIntent);
   1786 
   1787         NotificationManager notificationManager = (NotificationManager)
   1788             context.getSystemService(Context.NOTIFICATION_SERVICE);
   1789 
   1790         if (notifyType == PS_DISABLED || notifyType == CS_DISABLED) {
   1791             // cancel previous post notification
   1792             notificationManager.cancel(notificationId);
   1793         } else {
   1794             // update restricted state notification
   1795             notificationManager.notify(notificationId, mNotification);
   1796         }
   1797     }
   1798 
   1799     @Override
   1800     protected void onUpdateIccAvailability() {
   1801         if (mUiccController == null ) {
   1802             return;
   1803         }
   1804 
   1805         UiccCardApplication newUiccApplication =
   1806                 mUiccController.getUiccCardApplication(UiccController.APP_FAM_3GPP);
   1807 
   1808         if (mUiccApplcation != newUiccApplication) {
   1809             if (mUiccApplcation != null) {
   1810                 log("Removing stale icc objects.");
   1811                 mUiccApplcation.unregisterForReady(this);
   1812                 if (mIccRecords != null) {
   1813                     mIccRecords.unregisterForRecordsLoaded(this);
   1814                 }
   1815                 mIccRecords = null;
   1816                 mUiccApplcation = null;
   1817             }
   1818             if (newUiccApplication != null) {
   1819                 log("New card found");
   1820                 mUiccApplcation = newUiccApplication;
   1821                 mIccRecords = mUiccApplcation.getIccRecords();
   1822                 mUiccApplcation.registerForReady(this, EVENT_SIM_READY, null);
   1823                 if (mIccRecords != null) {
   1824                     mIccRecords.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null);
   1825                 }
   1826             }
   1827         }
   1828     }
   1829     @Override
   1830     protected void log(String s) {
   1831         Rlog.d(LOG_TAG, "[GsmSST] " + s);
   1832     }
   1833 
   1834     @Override
   1835     protected void loge(String s) {
   1836         Rlog.e(LOG_TAG, "[GsmSST] " + s);
   1837     }
   1838 
   1839     @Override
   1840     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
   1841         pw.println("GsmServiceStateTracker extends:");
   1842         super.dump(fd, pw, args);
   1843         pw.println(" mPhone=" + mPhone);
   1844         pw.println(" mSS=" + mSS);
   1845         pw.println(" mNewSS=" + mNewSS);
   1846         pw.println(" mCellLoc=" + mCellLoc);
   1847         pw.println(" mNewCellLoc=" + mNewCellLoc);
   1848         pw.println(" mPreferredNetworkType=" + mPreferredNetworkType);
   1849         pw.println(" mMaxDataCalls=" + mMaxDataCalls);
   1850         pw.println(" mNewMaxDataCalls=" + mNewMaxDataCalls);
   1851         pw.println(" mReasonDataDenied=" + mReasonDataDenied);
   1852         pw.println(" mNewReasonDataDenied=" + mNewReasonDataDenied);
   1853         pw.println(" mGsmRoaming=" + mGsmRoaming);
   1854         pw.println(" mDataRoaming=" + mDataRoaming);
   1855         pw.println(" mEmergencyOnly=" + mEmergencyOnly);
   1856         pw.println(" mNeedFixZoneAfterNitz=" + mNeedFixZoneAfterNitz);
   1857         pw.println(" mZoneOffset=" + mZoneOffset);
   1858         pw.println(" mZoneDst=" + mZoneDst);
   1859         pw.println(" mZoneTime=" + mZoneTime);
   1860         pw.println(" mGotCountryCode=" + mGotCountryCode);
   1861         pw.println(" mNitzUpdatedTime=" + mNitzUpdatedTime);
   1862         pw.println(" mSavedTimeZone=" + mSavedTimeZone);
   1863         pw.println(" mSavedTime=" + mSavedTime);
   1864         pw.println(" mSavedAtTime=" + mSavedAtTime);
   1865         pw.println(" mStartedGprsRegCheck=" + mStartedGprsRegCheck);
   1866         pw.println(" mReportedGprsNoReg=" + mReportedGprsNoReg);
   1867         pw.println(" mNotification=" + mNotification);
   1868         pw.println(" mWakeLock=" + mWakeLock);
   1869         pw.println(" mCurSpn=" + mCurSpn);
   1870         pw.println(" mCurShowSpn=" + mCurShowSpn);
   1871         pw.println(" mCurPlmn=" + mCurPlmn);
   1872         pw.println(" mCurShowPlmn=" + mCurShowPlmn);
   1873     }
   1874 }
   1875