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