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 
    952             if (operatorNumeric == null) {
    953                 if (DBG) log("operatorNumeric is null");
    954                 mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY, "");
    955                 mGotCountryCode = false;
    956                 mNitzUpdatedTime = false;
    957             } else {
    958                 String iso = "";
    959                 String mcc = "";
    960                 try{
    961                     mcc = operatorNumeric.substring(0, 3);
    962                     iso = MccTable.countryCodeForMcc(Integer.parseInt(mcc));
    963                 } catch ( NumberFormatException ex){
    964                     loge("pollStateDone: countryCodeForMcc error" + ex);
    965                 } catch ( StringIndexOutOfBoundsException ex) {
    966                     loge("pollStateDone: countryCodeForMcc error" + ex);
    967                 }
    968 
    969                 mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY, iso);
    970                 mGotCountryCode = true;
    971 
    972                 TimeZone zone = null;
    973 
    974                 if (!mNitzUpdatedTime && !mcc.equals("000") && !TextUtils.isEmpty(iso) &&
    975                         getAutoTimeZone()) {
    976 
    977                     // Test both paths if ignore nitz is true
    978                     boolean testOneUniqueOffsetPath = SystemProperties.getBoolean(
    979                                 TelephonyProperties.PROPERTY_IGNORE_NITZ, false) &&
    980                                     ((SystemClock.uptimeMillis() & 1) == 0);
    981 
    982                     ArrayList<TimeZone> uniqueZones = TimeUtils.getTimeZonesWithUniqueOffsets(iso);
    983                     if ((uniqueZones.size() == 1) || testOneUniqueOffsetPath) {
    984                         zone = uniqueZones.get(0);
    985                         if (DBG) {
    986                            log("pollStateDone: no nitz but one TZ for iso-cc=" + iso +
    987                                    " with zone.getID=" + zone.getID() +
    988                                    " testOneUniqueOffsetPath=" + testOneUniqueOffsetPath);
    989                         }
    990                         setAndBroadcastNetworkSetTimeZone(zone.getID());
    991                     } else {
    992                         if (DBG) {
    993                             log("pollStateDone: there are " + uniqueZones.size() +
    994                                 " unique offsets for iso-cc='" + iso +
    995                                 " testOneUniqueOffsetPath=" + testOneUniqueOffsetPath +
    996                                 "', do nothing");
    997                         }
    998                     }
    999                 }
   1000 
   1001                 if (shouldFixTimeZoneNow(mPhone, operatorNumeric, prevOperatorNumeric,
   1002                         mNeedFixZoneAfterNitz)) {
   1003                     // If the offset is (0, false) and the timezone property
   1004                     // is set, use the timezone property rather than
   1005                     // GMT.
   1006                     String zoneName = SystemProperties.get(TIMEZONE_PROPERTY);
   1007                     if (DBG) {
   1008                         log("pollStateDone: fix time zone zoneName='" + zoneName +
   1009                             "' mZoneOffset=" + mZoneOffset + " mZoneDst=" + mZoneDst +
   1010                             " iso-cc='" + iso +
   1011                             "' iso-cc-idx=" + Arrays.binarySearch(GMT_COUNTRY_CODES, iso));
   1012                     }
   1013 
   1014                     // "(mZoneOffset == 0) && (mZoneDst == false) &&
   1015                     //  (Arrays.binarySearch(GMT_COUNTRY_CODES, iso) < 0)"
   1016                     // means that we received a NITZ string telling
   1017                     // it is in GMT+0 w/ DST time zone
   1018                     // BUT iso tells is NOT, e.g, a wrong NITZ reporting
   1019                     // local time w/ 0 offset.
   1020                     if ((mZoneOffset == 0) && (mZoneDst == false) &&
   1021                         (zoneName != null) && (zoneName.length() > 0) &&
   1022                         (Arrays.binarySearch(GMT_COUNTRY_CODES, iso) < 0)) {
   1023                         zone = TimeZone.getDefault();
   1024                         if (mNeedFixZoneAfterNitz) {
   1025                             // For wrong NITZ reporting local time w/ 0 offset,
   1026                             // need adjust time to reflect default timezone setting
   1027                             long ctm = System.currentTimeMillis();
   1028                             long tzOffset = zone.getOffset(ctm);
   1029                             if (DBG) {
   1030                                 log("pollStateDone: tzOffset=" + tzOffset + " ltod=" +
   1031                                         TimeUtils.logTimeOfDay(ctm));
   1032                             }
   1033                             if (getAutoTime()) {
   1034                                 long adj = ctm - tzOffset;
   1035                                 if (DBG) log("pollStateDone: adj ltod=" +
   1036                                         TimeUtils.logTimeOfDay(adj));
   1037                                 setAndBroadcastNetworkSetTime(adj);
   1038                             } else {
   1039                                 // Adjust the saved NITZ time to account for tzOffset.
   1040                                 mSavedTime = mSavedTime - tzOffset;
   1041                             }
   1042                         }
   1043                         if (DBG) log("pollStateDone: using default TimeZone");
   1044                     } else if (iso.equals("")){
   1045                         // Country code not found.  This is likely a test network.
   1046                         // Get a TimeZone based only on the NITZ parameters (best guess).
   1047                         zone = getNitzTimeZone(mZoneOffset, mZoneDst, mZoneTime);
   1048                         if (DBG) log("pollStateDone: using NITZ TimeZone");
   1049                     } else {
   1050                         zone = TimeUtils.getTimeZone(mZoneOffset, mZoneDst, mZoneTime, iso);
   1051                         if (DBG) log("pollStateDone: using getTimeZone(off, dst, time, iso)");
   1052                     }
   1053 
   1054                     mNeedFixZoneAfterNitz = false;
   1055 
   1056                     if (zone != null) {
   1057                         log("pollStateDone: zone != null zone.getID=" + zone.getID());
   1058                         if (getAutoTimeZone()) {
   1059                             setAndBroadcastNetworkSetTimeZone(zone.getID());
   1060                         }
   1061                         saveNitzTimeZone(zone.getID());
   1062                     } else {
   1063                         log("pollStateDone: zone == null");
   1064                     }
   1065                 }
   1066             }
   1067 
   1068             mPhone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISROAMING,
   1069                 mSS.getRoaming() ? "true" : "false");
   1070 
   1071             mPhone.notifyServiceStateChanged(mSS);
   1072         }
   1073 
   1074         if (hasGprsAttached) {
   1075             mAttachedRegistrants.notifyRegistrants();
   1076         }
   1077 
   1078         if (hasGprsDetached) {
   1079             mDetachedRegistrants.notifyRegistrants();
   1080         }
   1081 
   1082         if (hasDataRegStateChanged || hasRilDataRadioTechnologyChanged) {
   1083             notifyDataRegStateRilRadioTechnologyChanged();
   1084             mPhone.notifyDataConnection(null);
   1085         }
   1086 
   1087         if (hasRoamingOn) {
   1088             mRoamingOnRegistrants.notifyRegistrants();
   1089         }
   1090 
   1091         if (hasRoamingOff) {
   1092             mRoamingOffRegistrants.notifyRegistrants();
   1093         }
   1094 
   1095         if (hasLocationChanged) {
   1096             mPhone.notifyLocationChanged();
   1097         }
   1098 
   1099         if (! isGprsConsistent(mSS.getDataRegState(), mSS.getVoiceRegState())) {
   1100             if (!mStartedGprsRegCheck && !mReportedGprsNoReg) {
   1101                 mStartedGprsRegCheck = true;
   1102 
   1103                 int check_period = Settings.Global.getInt(
   1104                         mPhone.getContext().getContentResolver(),
   1105                         Settings.Global.GPRS_REGISTER_CHECK_PERIOD_MS,
   1106                         DEFAULT_GPRS_CHECK_PERIOD_MILLIS);
   1107                 sendMessageDelayed(obtainMessage(EVENT_CHECK_REPORT_GPRS),
   1108                         check_period);
   1109             }
   1110         } else {
   1111             mReportedGprsNoReg = false;
   1112         }
   1113         // TODO: Add GsmCellIdenity updating, see CdmaLteServiceStateTracker.
   1114     }
   1115 
   1116     /**
   1117      * Check if GPRS got registered while voice is registered.
   1118      *
   1119      * @param dataRegState i.e. CGREG in GSM
   1120      * @param voiceRegState i.e. CREG in GSM
   1121      * @return false if device only register to voice but not gprs
   1122      */
   1123     private boolean isGprsConsistent(int dataRegState, int voiceRegState) {
   1124         return !((voiceRegState == ServiceState.STATE_IN_SERVICE) &&
   1125                 (dataRegState != ServiceState.STATE_IN_SERVICE));
   1126     }
   1127 
   1128     /**
   1129      * Returns a TimeZone object based only on parameters from the NITZ string.
   1130      */
   1131     private TimeZone getNitzTimeZone(int offset, boolean dst, long when) {
   1132         TimeZone guess = findTimeZone(offset, dst, when);
   1133         if (guess == null) {
   1134             // Couldn't find a proper timezone.  Perhaps the DST data is wrong.
   1135             guess = findTimeZone(offset, !dst, when);
   1136         }
   1137         if (DBG) log("getNitzTimeZone returning " + (guess == null ? guess : guess.getID()));
   1138         return guess;
   1139     }
   1140 
   1141     private TimeZone findTimeZone(int offset, boolean dst, long when) {
   1142         int rawOffset = offset;
   1143         if (dst) {
   1144             rawOffset -= 3600000;
   1145         }
   1146         String[] zones = TimeZone.getAvailableIDs(rawOffset);
   1147         TimeZone guess = null;
   1148         Date d = new Date(when);
   1149         for (String zone : zones) {
   1150             TimeZone tz = TimeZone.getTimeZone(zone);
   1151             if (tz.getOffset(when) == offset &&
   1152                 tz.inDaylightTime(d) == dst) {
   1153                 guess = tz;
   1154                 break;
   1155             }
   1156         }
   1157 
   1158         return guess;
   1159     }
   1160 
   1161     private void queueNextSignalStrengthPoll() {
   1162         if (mDontPollSignalStrength) {
   1163             // The radio is telling us about signal strength changes
   1164             // we don't have to ask it
   1165             return;
   1166         }
   1167 
   1168         Message msg;
   1169 
   1170         msg = obtainMessage();
   1171         msg.what = EVENT_POLL_SIGNAL_STRENGTH;
   1172 
   1173         long nextTime;
   1174 
   1175         // TODO Don't poll signal strength if screen is off
   1176         sendMessageDelayed(msg, POLL_PERIOD_MILLIS);
   1177     }
   1178 
   1179     /**
   1180      * Set restricted state based on the OnRestrictedStateChanged notification
   1181      * If any voice or packet restricted state changes, trigger a UI
   1182      * notification and notify registrants when sim is ready.
   1183      *
   1184      * @param ar an int value of RIL_RESTRICTED_STATE_*
   1185      */
   1186     private void onRestrictedStateChanged(AsyncResult ar) {
   1187         RestrictedState newRs = new RestrictedState();
   1188 
   1189         if (DBG) log("onRestrictedStateChanged: E rs "+ mRestrictedState);
   1190 
   1191         if (ar.exception == null) {
   1192             int[] ints = (int[])ar.result;
   1193             int state = ints[0];
   1194 
   1195             newRs.setCsEmergencyRestricted(
   1196                     ((state & RILConstants.RIL_RESTRICTED_STATE_CS_EMERGENCY) != 0) ||
   1197                     ((state & RILConstants.RIL_RESTRICTED_STATE_CS_ALL) != 0) );
   1198             //ignore the normal call and data restricted state before SIM READY
   1199             if (mUiccApplcation != null && mUiccApplcation.getState() == AppState.APPSTATE_READY) {
   1200                 newRs.setCsNormalRestricted(
   1201                         ((state & RILConstants.RIL_RESTRICTED_STATE_CS_NORMAL) != 0) ||
   1202                         ((state & RILConstants.RIL_RESTRICTED_STATE_CS_ALL) != 0) );
   1203                 newRs.setPsRestricted(
   1204                         (state & RILConstants.RIL_RESTRICTED_STATE_PS_ALL)!= 0);
   1205             }
   1206 
   1207             if (DBG) log("onRestrictedStateChanged: new rs "+ newRs);
   1208 
   1209             if (!mRestrictedState.isPsRestricted() && newRs.isPsRestricted()) {
   1210                 mPsRestrictEnabledRegistrants.notifyRegistrants();
   1211                 setNotification(PS_ENABLED);
   1212             } else if (mRestrictedState.isPsRestricted() && !newRs.isPsRestricted()) {
   1213                 mPsRestrictDisabledRegistrants.notifyRegistrants();
   1214                 setNotification(PS_DISABLED);
   1215             }
   1216 
   1217             /**
   1218              * There are two kind of cs restriction, normal and emergency. So
   1219              * there are 4 x 4 combinations in current and new restricted states
   1220              * and we only need to notify when state is changed.
   1221              */
   1222             if (mRestrictedState.isCsRestricted()) {
   1223                 if (!newRs.isCsRestricted()) {
   1224                     // remove all restriction
   1225                     setNotification(CS_DISABLED);
   1226                 } else if (!newRs.isCsNormalRestricted()) {
   1227                     // remove normal restriction
   1228                     setNotification(CS_EMERGENCY_ENABLED);
   1229                 } else if (!newRs.isCsEmergencyRestricted()) {
   1230                     // remove emergency restriction
   1231                     setNotification(CS_NORMAL_ENABLED);
   1232                 }
   1233             } else if (mRestrictedState.isCsEmergencyRestricted() &&
   1234                     !mRestrictedState.isCsNormalRestricted()) {
   1235                 if (!newRs.isCsRestricted()) {
   1236                     // remove all restriction
   1237                     setNotification(CS_DISABLED);
   1238                 } else if (newRs.isCsRestricted()) {
   1239                     // enable all restriction
   1240                     setNotification(CS_ENABLED);
   1241                 } else if (newRs.isCsNormalRestricted()) {
   1242                     // remove emergency restriction and enable normal restriction
   1243                     setNotification(CS_NORMAL_ENABLED);
   1244                 }
   1245             } else if (!mRestrictedState.isCsEmergencyRestricted() &&
   1246                     mRestrictedState.isCsNormalRestricted()) {
   1247                 if (!newRs.isCsRestricted()) {
   1248                     // remove all restriction
   1249                     setNotification(CS_DISABLED);
   1250                 } else if (newRs.isCsRestricted()) {
   1251                     // enable all restriction
   1252                     setNotification(CS_ENABLED);
   1253                 } else if (newRs.isCsEmergencyRestricted()) {
   1254                     // remove normal restriction and enable emergency restriction
   1255                     setNotification(CS_EMERGENCY_ENABLED);
   1256                 }
   1257             } else {
   1258                 if (newRs.isCsRestricted()) {
   1259                     // enable all restriction
   1260                     setNotification(CS_ENABLED);
   1261                 } else if (newRs.isCsEmergencyRestricted()) {
   1262                     // enable emergency restriction
   1263                     setNotification(CS_EMERGENCY_ENABLED);
   1264                 } else if (newRs.isCsNormalRestricted()) {
   1265                     // enable normal restriction
   1266                     setNotification(CS_NORMAL_ENABLED);
   1267                 }
   1268             }
   1269 
   1270             mRestrictedState = newRs;
   1271         }
   1272         log("onRestrictedStateChanged: X rs "+ mRestrictedState);
   1273     }
   1274 
   1275     /** code is registration state 0-5 from TS 27.007 7.2 */
   1276     private int regCodeToServiceState(int code) {
   1277         switch (code) {
   1278             case 0:
   1279             case 2: // 2 is "searching"
   1280             case 3: // 3 is "registration denied"
   1281             case 4: // 4 is "unknown" no vaild in current baseband
   1282             case 10:// same as 0, but indicates that emergency call is possible.
   1283             case 12:// same as 2, but indicates that emergency call is possible.
   1284             case 13:// same as 3, but indicates that emergency call is possible.
   1285             case 14:// same as 4, but indicates that emergency call is possible.
   1286                 return ServiceState.STATE_OUT_OF_SERVICE;
   1287 
   1288             case 1:
   1289                 return ServiceState.STATE_IN_SERVICE;
   1290 
   1291             case 5:
   1292                 // in service, roam
   1293                 return ServiceState.STATE_IN_SERVICE;
   1294 
   1295             default:
   1296                 loge("regCodeToServiceState: unexpected service state " + code);
   1297                 return ServiceState.STATE_OUT_OF_SERVICE;
   1298         }
   1299     }
   1300 
   1301 
   1302     /**
   1303      * code is registration state 0-5 from TS 27.007 7.2
   1304      * returns true if registered roam, false otherwise
   1305      */
   1306     private boolean regCodeIsRoaming (int code) {
   1307         return ServiceState.RIL_REG_STATE_ROAMING == code;
   1308     }
   1309 
   1310     /**
   1311      * Set roaming state if operator mcc is the same as sim mcc
   1312      * and ons is different from spn
   1313      *
   1314      * @param s ServiceState hold current ons
   1315      * @return true if same operator
   1316      */
   1317     private boolean isSameNamedOperators(ServiceState s) {
   1318         String spn = SystemProperties.get(TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA, "empty");
   1319 
   1320         String onsl = s.getOperatorAlphaLong();
   1321         String onss = s.getOperatorAlphaShort();
   1322 
   1323         boolean equalsOnsl = onsl != null && spn.equals(onsl);
   1324         boolean equalsOnss = onss != null && spn.equals(onss);
   1325 
   1326         return currentMccEqualsSimMcc(s) && (equalsOnsl || equalsOnss);
   1327     }
   1328 
   1329     /**
   1330      * Compare SIM MCC with Operator MCC
   1331      *
   1332      * @param s ServiceState hold current ons
   1333      * @return true if both are same
   1334      */
   1335     private boolean currentMccEqualsSimMcc(ServiceState s) {
   1336         String simNumeric = SystemProperties.get(
   1337                 TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC, "");
   1338         String operatorNumeric = s.getOperatorNumeric();
   1339         boolean equalsMcc = true;
   1340 
   1341         try {
   1342             equalsMcc = simNumeric.substring(0, 3).
   1343                     equals(operatorNumeric.substring(0, 3));
   1344         } catch (Exception e){
   1345         }
   1346         return equalsMcc;
   1347     }
   1348 
   1349     /**
   1350      * Do not set roaming state in case of oprators considered non-roaming.
   1351      *
   1352      + Can use mcc or mcc+mnc as item of config_operatorConsideredNonRoaming.
   1353      * For example, 302 or 21407. If mcc or mcc+mnc match with operator,
   1354      * don't set roaming state.
   1355      *
   1356      * @param s ServiceState hold current ons
   1357      * @return false for roaming state set
   1358      */
   1359     private boolean isOperatorConsideredNonRoaming(ServiceState s) {
   1360         String operatorNumeric = s.getOperatorNumeric();
   1361         String[] numericArray = mPhone.getContext().getResources().getStringArray(
   1362                     com.android.internal.R.array.config_operatorConsideredNonRoaming);
   1363 
   1364         if (numericArray.length == 0 || operatorNumeric == null)
   1365             return false;
   1366 
   1367         for (String numeric : numericArray) {
   1368             if (operatorNumeric.startsWith(numeric))
   1369                 return true;
   1370         }
   1371         return false;
   1372     }
   1373 
   1374     private boolean isSameNamedOperatorConsideredRoaming(ServiceState s) {
   1375         String operatorNumeric = s.getOperatorNumeric();
   1376         String[] numericArray = mPhone.getContext().getResources().getStringArray(
   1377                     com.android.internal.R.array.config_sameNamedOperatorConsideredRoaming);
   1378 
   1379         if (numericArray.length == 0 || operatorNumeric == null)
   1380             return false;
   1381 
   1382         for (String numeric : numericArray) {
   1383             if (operatorNumeric.startsWith(numeric))
   1384                 return true;
   1385             else
   1386                 return false;
   1387         }
   1388         return false;
   1389     }
   1390 
   1391     /**
   1392      * @return The current GPRS state. IN_SERVICE is the same as "attached"
   1393      * and OUT_OF_SERVICE is the same as detached.
   1394      */
   1395     @Override
   1396     public int getCurrentDataConnectionState() {
   1397         return mSS.getDataRegState();
   1398     }
   1399 
   1400     /**
   1401      * @return true if phone is camping on a technology (eg UMTS)
   1402      * that could support voice and data simultaneously.
   1403      */
   1404     @Override
   1405     public boolean isConcurrentVoiceAndDataAllowed() {
   1406         return (mSS.getRilVoiceRadioTechnology() >= ServiceState.RIL_RADIO_TECHNOLOGY_UMTS);
   1407     }
   1408 
   1409     /**
   1410      * @return the current cell location information. Prefer Gsm location
   1411      * information if available otherwise return LTE location information
   1412      */
   1413     public CellLocation getCellLocation() {
   1414         if ((mCellLoc.getLac() >= 0) && (mCellLoc.getCid() >= 0)) {
   1415             if (DBG) log("getCellLocation(): X good mCellLoc=" + mCellLoc);
   1416             return mCellLoc;
   1417         } else {
   1418             List<CellInfo> result = getAllCellInfo();
   1419             if (result != null) {
   1420                 // A hack to allow tunneling of LTE information via GsmCellLocation
   1421                 // so that older Network Location Providers can return some information
   1422                 // on LTE only networks, see bug 9228974.
   1423                 //
   1424                 // We'll search the return CellInfo array preferring GSM/WCDMA
   1425                 // data, but if there is none we'll tunnel the first LTE information
   1426                 // in the list.
   1427                 //
   1428                 // The tunnel'd LTE information is returned as follows:
   1429                 //   LAC = TAC field
   1430                 //   CID = CI field
   1431                 //   PSC = 0.
   1432                 GsmCellLocation cellLocOther = new GsmCellLocation();
   1433                 for (CellInfo ci : result) {
   1434                     if (ci instanceof CellInfoGsm) {
   1435                         CellInfoGsm cellInfoGsm = (CellInfoGsm)ci;
   1436                         CellIdentityGsm cellIdentityGsm = cellInfoGsm.getCellIdentity();
   1437                         cellLocOther.setLacAndCid(cellIdentityGsm.getLac(),
   1438                                 cellIdentityGsm.getCid());
   1439                         cellLocOther.setPsc(cellIdentityGsm.getPsc());
   1440                         if (DBG) log("getCellLocation(): X ret GSM info=" + cellLocOther);
   1441                         return cellLocOther;
   1442                     } else if (ci instanceof CellInfoWcdma) {
   1443                         CellInfoWcdma cellInfoWcdma = (CellInfoWcdma)ci;
   1444                         CellIdentityWcdma cellIdentityWcdma = cellInfoWcdma.getCellIdentity();
   1445                         cellLocOther.setLacAndCid(cellIdentityWcdma.getLac(),
   1446                                 cellIdentityWcdma.getCid());
   1447                         cellLocOther.setPsc(cellIdentityWcdma.getPsc());
   1448                         if (DBG) log("getCellLocation(): X ret WCDMA info=" + cellLocOther);
   1449                         return cellLocOther;
   1450                     } else if ((ci instanceof CellInfoLte) &&
   1451                             ((cellLocOther.getLac() < 0) || (cellLocOther.getCid() < 0))) {
   1452                         // We'll return the first good LTE info we get if there is no better answer
   1453                         CellInfoLte cellInfoLte = (CellInfoLte)ci;
   1454                         CellIdentityLte cellIdentityLte = cellInfoLte.getCellIdentity();
   1455                         if ((cellIdentityLte.getTac() != Integer.MAX_VALUE)
   1456                                 && (cellIdentityLte.getCi() != Integer.MAX_VALUE)) {
   1457                             cellLocOther.setLacAndCid(cellIdentityLte.getTac(),
   1458                                     cellIdentityLte.getCi());
   1459                             cellLocOther.setPsc(0);
   1460                             if (DBG) {
   1461                                 log("getCellLocation(): possible LTE cellLocOther=" + cellLocOther);
   1462                             }
   1463                         }
   1464                     }
   1465                 }
   1466                 if (DBG) {
   1467                     log("getCellLocation(): X ret best answer cellLocOther=" + cellLocOther);
   1468                 }
   1469                 return cellLocOther;
   1470             } else {
   1471                 if (DBG) {
   1472                     log("getCellLocation(): X empty mCellLoc and CellInfo mCellLoc=" + mCellLoc);
   1473                 }
   1474                 return mCellLoc;
   1475             }
   1476         }
   1477     }
   1478 
   1479     /**
   1480      * nitzReceiveTime is time_t that the NITZ time was posted
   1481      */
   1482     private void setTimeFromNITZString (String nitz, long nitzReceiveTime) {
   1483         // "yy/mm/dd,hh:mm:ss(+/-)tz"
   1484         // tz is in number of quarter-hours
   1485 
   1486         long start = SystemClock.elapsedRealtime();
   1487         if (DBG) {log("NITZ: " + nitz + "," + nitzReceiveTime +
   1488                         " start=" + start + " delay=" + (start - nitzReceiveTime));
   1489         }
   1490 
   1491         try {
   1492             /* NITZ time (hour:min:sec) will be in UTC but it supplies the timezone
   1493              * offset as well (which we won't worry about until later) */
   1494             Calendar c = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
   1495 
   1496             c.clear();
   1497             c.set(Calendar.DST_OFFSET, 0);
   1498 
   1499             String[] nitzSubs = nitz.split("[/:,+-]");
   1500 
   1501             int year = 2000 + Integer.parseInt(nitzSubs[0]);
   1502             c.set(Calendar.YEAR, year);
   1503 
   1504             // month is 0 based!
   1505             int month = Integer.parseInt(nitzSubs[1]) - 1;
   1506             c.set(Calendar.MONTH, month);
   1507 
   1508             int date = Integer.parseInt(nitzSubs[2]);
   1509             c.set(Calendar.DATE, date);
   1510 
   1511             int hour = Integer.parseInt(nitzSubs[3]);
   1512             c.set(Calendar.HOUR, hour);
   1513 
   1514             int minute = Integer.parseInt(nitzSubs[4]);
   1515             c.set(Calendar.MINUTE, minute);
   1516 
   1517             int second = Integer.parseInt(nitzSubs[5]);
   1518             c.set(Calendar.SECOND, second);
   1519 
   1520             boolean sign = (nitz.indexOf('-') == -1);
   1521 
   1522             int tzOffset = Integer.parseInt(nitzSubs[6]);
   1523 
   1524             int dst = (nitzSubs.length >= 8 ) ? Integer.parseInt(nitzSubs[7])
   1525                                               : 0;
   1526 
   1527             // The zone offset received from NITZ is for current local time,
   1528             // so DST correction is already applied.  Don't add it again.
   1529             //
   1530             // tzOffset += dst * 4;
   1531             //
   1532             // We could unapply it if we wanted the raw offset.
   1533 
   1534             tzOffset = (sign ? 1 : -1) * tzOffset * 15 * 60 * 1000;
   1535 
   1536             TimeZone    zone = null;
   1537 
   1538             // As a special extension, the Android emulator appends the name of
   1539             // the host computer's timezone to the nitz string. this is zoneinfo
   1540             // timezone name of the form Area!Location or Area!Location!SubLocation
   1541             // so we need to convert the ! into /
   1542             if (nitzSubs.length >= 9) {
   1543                 String  tzname = nitzSubs[8].replace('!','/');
   1544                 zone = TimeZone.getTimeZone( tzname );
   1545             }
   1546 
   1547             String iso = SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY);
   1548 
   1549             if (zone == null) {
   1550 
   1551                 if (mGotCountryCode) {
   1552                     if (iso != null && iso.length() > 0) {
   1553                         zone = TimeUtils.getTimeZone(tzOffset, dst != 0,
   1554                                 c.getTimeInMillis(),
   1555                                 iso);
   1556                     } else {
   1557                         // We don't have a valid iso country code.  This is
   1558                         // most likely because we're on a test network that's
   1559                         // using a bogus MCC (eg, "001"), so get a TimeZone
   1560                         // based only on the NITZ parameters.
   1561                         zone = getNitzTimeZone(tzOffset, (dst != 0), c.getTimeInMillis());
   1562                     }
   1563                 }
   1564             }
   1565 
   1566             if ((zone == null) || (mZoneOffset != tzOffset) || (mZoneDst != (dst != 0))){
   1567                 // We got the time before the country or the zone has changed
   1568                 // so we don't know how to identify the DST rules yet.  Save
   1569                 // the information and hope to fix it up later.
   1570 
   1571                 mNeedFixZoneAfterNitz = true;
   1572                 mZoneOffset  = tzOffset;
   1573                 mZoneDst     = dst != 0;
   1574                 mZoneTime    = c.getTimeInMillis();
   1575             }
   1576 
   1577             if (zone != null) {
   1578                 if (getAutoTimeZone()) {
   1579                     setAndBroadcastNetworkSetTimeZone(zone.getID());
   1580                 }
   1581                 saveNitzTimeZone(zone.getID());
   1582             }
   1583 
   1584             String ignore = SystemProperties.get("gsm.ignore-nitz");
   1585             if (ignore != null && ignore.equals("yes")) {
   1586                 log("NITZ: Not setting clock because gsm.ignore-nitz is set");
   1587                 return;
   1588             }
   1589 
   1590             try {
   1591                 mWakeLock.acquire();
   1592 
   1593                 if (getAutoTime()) {
   1594                     long millisSinceNitzReceived
   1595                             = SystemClock.elapsedRealtime() - nitzReceiveTime;
   1596 
   1597                     if (millisSinceNitzReceived < 0) {
   1598                         // Sanity check: something is wrong
   1599                         if (DBG) {
   1600                             log("NITZ: not setting time, clock has rolled "
   1601                                             + "backwards since NITZ time was received, "
   1602                                             + nitz);
   1603                         }
   1604                         return;
   1605                     }
   1606 
   1607                     if (millisSinceNitzReceived > Integer.MAX_VALUE) {
   1608                         // If the time is this far off, something is wrong > 24 days!
   1609                         if (DBG) {
   1610                             log("NITZ: not setting time, processing has taken "
   1611                                         + (millisSinceNitzReceived / (1000 * 60 * 60 * 24))
   1612                                         + " days");
   1613                         }
   1614                         return;
   1615                     }
   1616 
   1617                     // Note: with range checks above, cast to int is safe
   1618                     c.add(Calendar.MILLISECOND, (int)millisSinceNitzReceived);
   1619 
   1620                     if (DBG) {
   1621                         log("NITZ: Setting time of day to " + c.getTime()
   1622                             + " NITZ receive delay(ms): " + millisSinceNitzReceived
   1623                             + " gained(ms): "
   1624                             + (c.getTimeInMillis() - System.currentTimeMillis())
   1625                             + " from " + nitz);
   1626                     }
   1627 
   1628                     setAndBroadcastNetworkSetTime(c.getTimeInMillis());
   1629                     Rlog.i(LOG_TAG, "NITZ: after Setting time of day");
   1630                 }
   1631                 SystemProperties.set("gsm.nitz.time", String.valueOf(c.getTimeInMillis()));
   1632                 saveNitzTime(c.getTimeInMillis());
   1633                 if (VDBG) {
   1634                     long end = SystemClock.elapsedRealtime();
   1635                     log("NITZ: end=" + end + " dur=" + (end - start));
   1636                 }
   1637                 mNitzUpdatedTime = true;
   1638             } finally {
   1639                 mWakeLock.release();
   1640             }
   1641         } catch (RuntimeException ex) {
   1642             loge("NITZ: Parsing NITZ time " + nitz + " ex=" + ex);
   1643         }
   1644     }
   1645 
   1646     private boolean getAutoTime() {
   1647         try {
   1648             return Settings.Global.getInt(mPhone.getContext().getContentResolver(),
   1649                     Settings.Global.AUTO_TIME) > 0;
   1650         } catch (SettingNotFoundException snfe) {
   1651             return true;
   1652         }
   1653     }
   1654 
   1655     private boolean getAutoTimeZone() {
   1656         try {
   1657             return Settings.Global.getInt(mPhone.getContext().getContentResolver(),
   1658                     Settings.Global.AUTO_TIME_ZONE) > 0;
   1659         } catch (SettingNotFoundException snfe) {
   1660             return true;
   1661         }
   1662     }
   1663 
   1664     private void saveNitzTimeZone(String zoneId) {
   1665         mSavedTimeZone = zoneId;
   1666     }
   1667 
   1668     private void saveNitzTime(long time) {
   1669         mSavedTime = time;
   1670         mSavedAtTime = SystemClock.elapsedRealtime();
   1671     }
   1672 
   1673     /**
   1674      * Set the timezone and send out a sticky broadcast so the system can
   1675      * determine if the timezone was set by the carrier.
   1676      *
   1677      * @param zoneId timezone set by carrier
   1678      */
   1679     private void setAndBroadcastNetworkSetTimeZone(String zoneId) {
   1680         if (DBG) log("setAndBroadcastNetworkSetTimeZone: setTimeZone=" + zoneId);
   1681         AlarmManager alarm =
   1682             (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE);
   1683         alarm.setTimeZone(zoneId);
   1684         Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE);
   1685         intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
   1686         intent.putExtra("time-zone", zoneId);
   1687         mPhone.getContext().sendStickyBroadcastAsUser(intent, UserHandle.ALL);
   1688         if (DBG) {
   1689             log("setAndBroadcastNetworkSetTimeZone: call alarm.setTimeZone and broadcast zoneId=" +
   1690                 zoneId);
   1691         }
   1692     }
   1693 
   1694     /**
   1695      * Set the time and Send out a sticky broadcast so the system can determine
   1696      * if the time was set by the carrier.
   1697      *
   1698      * @param time time set by network
   1699      */
   1700     private void setAndBroadcastNetworkSetTime(long time) {
   1701         if (DBG) log("setAndBroadcastNetworkSetTime: time=" + time + "ms");
   1702         SystemClock.setCurrentTimeMillis(time);
   1703         Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIME);
   1704         intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
   1705         intent.putExtra("time", time);
   1706         mPhone.getContext().sendStickyBroadcastAsUser(intent, UserHandle.ALL);
   1707     }
   1708 
   1709     private void revertToNitzTime() {
   1710         if (Settings.Global.getInt(mPhone.getContext().getContentResolver(),
   1711                 Settings.Global.AUTO_TIME, 0) == 0) {
   1712             return;
   1713         }
   1714         if (DBG) {
   1715             log("Reverting to NITZ Time: mSavedTime=" + mSavedTime
   1716                 + " mSavedAtTime=" + mSavedAtTime);
   1717         }
   1718         if (mSavedTime != 0 && mSavedAtTime != 0) {
   1719             setAndBroadcastNetworkSetTime(mSavedTime
   1720                     + (SystemClock.elapsedRealtime() - mSavedAtTime));
   1721         }
   1722     }
   1723 
   1724     private void revertToNitzTimeZone() {
   1725         if (Settings.Global.getInt(mPhone.getContext().getContentResolver(),
   1726                 Settings.Global.AUTO_TIME_ZONE, 0) == 0) {
   1727             return;
   1728         }
   1729         if (DBG) log("Reverting to NITZ TimeZone: tz='" + mSavedTimeZone);
   1730         if (mSavedTimeZone != null) {
   1731             setAndBroadcastNetworkSetTimeZone(mSavedTimeZone);
   1732         }
   1733     }
   1734 
   1735     /**
   1736      * Post a notification to NotificationManager for restricted state
   1737      *
   1738      * @param notifyType is one state of PS/CS_*_ENABLE/DISABLE
   1739      */
   1740     private void setNotification(int notifyType) {
   1741 
   1742         if (DBG) log("setNotification: create notification " + notifyType);
   1743         Context context = mPhone.getContext();
   1744 
   1745         mNotification = new Notification();
   1746         mNotification.when = System.currentTimeMillis();
   1747         mNotification.flags = Notification.FLAG_AUTO_CANCEL;
   1748         mNotification.icon = com.android.internal.R.drawable.stat_sys_warning;
   1749         Intent intent = new Intent();
   1750         mNotification.contentIntent = PendingIntent
   1751         .getActivity(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
   1752 
   1753         CharSequence details = "";
   1754         CharSequence title = context.getText(com.android.internal.R.string.RestrictedChangedTitle);
   1755         int notificationId = CS_NOTIFICATION;
   1756 
   1757         switch (notifyType) {
   1758         case PS_ENABLED:
   1759             notificationId = PS_NOTIFICATION;
   1760             details = context.getText(com.android.internal.R.string.RestrictedOnData);
   1761             break;
   1762         case PS_DISABLED:
   1763             notificationId = PS_NOTIFICATION;
   1764             break;
   1765         case CS_ENABLED:
   1766             details = context.getText(com.android.internal.R.string.RestrictedOnAllVoice);
   1767             break;
   1768         case CS_NORMAL_ENABLED:
   1769             details = context.getText(com.android.internal.R.string.RestrictedOnNormal);
   1770             break;
   1771         case CS_EMERGENCY_ENABLED:
   1772             details = context.getText(com.android.internal.R.string.RestrictedOnEmergency);
   1773             break;
   1774         case CS_DISABLED:
   1775             // do nothing and cancel the notification later
   1776             break;
   1777         }
   1778 
   1779         if (DBG) log("setNotification: put notification " + title + " / " +details);
   1780         mNotification.tickerText = title;
   1781         mNotification.setLatestEventInfo(context, title, details,
   1782                 mNotification.contentIntent);
   1783 
   1784         NotificationManager notificationManager = (NotificationManager)
   1785             context.getSystemService(Context.NOTIFICATION_SERVICE);
   1786 
   1787         if (notifyType == PS_DISABLED || notifyType == CS_DISABLED) {
   1788             // cancel previous post notification
   1789             notificationManager.cancel(notificationId);
   1790         } else {
   1791             // update restricted state notification
   1792             notificationManager.notify(notificationId, mNotification);
   1793         }
   1794     }
   1795 
   1796     @Override
   1797     protected void onUpdateIccAvailability() {
   1798         if (mUiccController == null ) {
   1799             return;
   1800         }
   1801 
   1802         UiccCardApplication newUiccApplication =
   1803                 mUiccController.getUiccCardApplication(UiccController.APP_FAM_3GPP);
   1804 
   1805         if (mUiccApplcation != newUiccApplication) {
   1806             if (mUiccApplcation != null) {
   1807                 log("Removing stale icc objects.");
   1808                 mUiccApplcation.unregisterForReady(this);
   1809                 if (mIccRecords != null) {
   1810                     mIccRecords.unregisterForRecordsLoaded(this);
   1811                 }
   1812                 mIccRecords = null;
   1813                 mUiccApplcation = null;
   1814             }
   1815             if (newUiccApplication != null) {
   1816                 log("New card found");
   1817                 mUiccApplcation = newUiccApplication;
   1818                 mIccRecords = mUiccApplcation.getIccRecords();
   1819                 mUiccApplcation.registerForReady(this, EVENT_SIM_READY, null);
   1820                 if (mIccRecords != null) {
   1821                     mIccRecords.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null);
   1822                 }
   1823             }
   1824         }
   1825     }
   1826     @Override
   1827     protected void log(String s) {
   1828         Rlog.d(LOG_TAG, "[GsmSST] " + s);
   1829     }
   1830 
   1831     @Override
   1832     protected void loge(String s) {
   1833         Rlog.e(LOG_TAG, "[GsmSST] " + s);
   1834     }
   1835 
   1836     @Override
   1837     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
   1838         pw.println("GsmServiceStateTracker extends:");
   1839         super.dump(fd, pw, args);
   1840         pw.println(" mPhone=" + mPhone);
   1841         pw.println(" mSS=" + mSS);
   1842         pw.println(" mNewSS=" + mNewSS);
   1843         pw.println(" mCellLoc=" + mCellLoc);
   1844         pw.println(" mNewCellLoc=" + mNewCellLoc);
   1845         pw.println(" mPreferredNetworkType=" + mPreferredNetworkType);
   1846         pw.println(" mMaxDataCalls=" + mMaxDataCalls);
   1847         pw.println(" mNewMaxDataCalls=" + mNewMaxDataCalls);
   1848         pw.println(" mReasonDataDenied=" + mReasonDataDenied);
   1849         pw.println(" mNewReasonDataDenied=" + mNewReasonDataDenied);
   1850         pw.println(" mGsmRoaming=" + mGsmRoaming);
   1851         pw.println(" mDataRoaming=" + mDataRoaming);
   1852         pw.println(" mEmergencyOnly=" + mEmergencyOnly);
   1853         pw.println(" mNeedFixZoneAfterNitz=" + mNeedFixZoneAfterNitz);
   1854         pw.println(" mZoneOffset=" + mZoneOffset);
   1855         pw.println(" mZoneDst=" + mZoneDst);
   1856         pw.println(" mZoneTime=" + mZoneTime);
   1857         pw.println(" mGotCountryCode=" + mGotCountryCode);
   1858         pw.println(" mNitzUpdatedTime=" + mNitzUpdatedTime);
   1859         pw.println(" mSavedTimeZone=" + mSavedTimeZone);
   1860         pw.println(" mSavedTime=" + mSavedTime);
   1861         pw.println(" mSavedAtTime=" + mSavedAtTime);
   1862         pw.println(" mStartedGprsRegCheck=" + mStartedGprsRegCheck);
   1863         pw.println(" mReportedGprsNoReg=" + mReportedGprsNoReg);
   1864         pw.println(" mNotification=" + mNotification);
   1865         pw.println(" mWakeLock=" + mWakeLock);
   1866         pw.println(" mCurSpn=" + mCurSpn);
   1867         pw.println(" mCurShowSpn=" + mCurShowSpn);
   1868         pw.println(" mCurPlmn=" + mCurPlmn);
   1869         pw.println(" mCurShowPlmn=" + mCurShowPlmn);
   1870     }
   1871 }
   1872