ServiceStateTracker.java revision 5fb811ff076aa6b4a9ceca6edaf504a4c6d9ad20
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
17package com.android.internal.telephony;
18
19import android.os.AsyncResult;
20import android.os.Handler;
21import android.os.Message;
22import android.os.Registrant;
23import android.os.RegistrantList;
24import android.telephony.CellInfo;
25import android.telephony.ServiceState;
26import android.telephony.SignalStrength;
27import android.util.TimeUtils;
28
29import java.io.FileDescriptor;
30import java.io.PrintWriter;
31import java.util.ArrayList;
32import java.util.List;
33
34import com.android.internal.telephony.dataconnection.DcTrackerBase;
35import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppState;
36import com.android.internal.telephony.uicc.IccRecords;
37import com.android.internal.telephony.uicc.UiccCardApplication;
38import com.android.internal.telephony.uicc.UiccController;
39
40/**
41 * {@hide}
42 */
43public abstract class ServiceStateTracker extends Handler {
44    protected  static final boolean DBG = true;
45    protected static final boolean VDBG = false;
46
47    protected static final String PROP_FORCE_ROAMING = "telephony.test.forceRoaming";
48
49    protected CommandsInterface mCi;
50    protected UiccController mUiccController = null;
51    protected UiccCardApplication mUiccApplcation = null;
52    protected IccRecords mIccRecords = null;
53
54    protected PhoneBase mPhoneBase;
55
56    public ServiceState mSS = new ServiceState();
57    protected ServiceState mNewSS = new ServiceState();
58
59    protected List<CellInfo> mLastCellInfoList = null;
60    protected CellInfo mLastCellInfo = null;
61
62    // This is final as subclasses alias to a more specific type
63    // so we don't want the reference to change.
64    protected final CellInfo mCellInfo;
65
66    protected SignalStrength mSignalStrength = new SignalStrength();
67
68    // TODO - this should not be public, right now used externally GsmConnetion.
69    public RestrictedState mRestrictedState = new RestrictedState();
70
71    /* The otaspMode passed to PhoneStateListener#onOtaspChanged */
72    static public final int OTASP_UNINITIALIZED = 0;
73    static public final int OTASP_UNKNOWN = 1;
74    static public final int OTASP_NEEDED = 2;
75    static public final int OTASP_NOT_NEEDED = 3;
76
77    /**
78     * A unique identifier to track requests associated with a poll
79     * and ignore stale responses.  The value is a count-down of
80     * expected responses in this pollingContext.
81     */
82    protected int[] mPollingContext;
83    protected boolean mDesiredPowerState;
84
85    /**
86     * By default, strength polling is enabled.  However, if we're
87     * getting unsolicited signal strength updates from the radio, set
88     * value to true and don't bother polling any more.
89     */
90    protected boolean mDontPollSignalStrength = false;
91
92    protected RegistrantList mRoamingOnRegistrants = new RegistrantList();
93    protected RegistrantList mRoamingOffRegistrants = new RegistrantList();
94    protected RegistrantList mAttachedRegistrants = new RegistrantList();
95    protected RegistrantList mDetachedRegistrants = new RegistrantList();
96    protected RegistrantList mNetworkAttachedRegistrants = new RegistrantList();
97    protected RegistrantList mPsRestrictEnabledRegistrants = new RegistrantList();
98    protected RegistrantList mPsRestrictDisabledRegistrants = new RegistrantList();
99
100    /* Radio power off pending flag and tag counter */
101    private boolean mPendingRadioPowerOffAfterDataOff = false;
102    private int mPendingRadioPowerOffAfterDataOffTag = 0;
103
104    /** Signal strength poll rate. */
105    protected static final int POLL_PERIOD_MILLIS = 20 * 1000;
106
107    /** Waiting period before recheck gprs and voice registration. */
108    public static final int DEFAULT_GPRS_CHECK_PERIOD_MILLIS = 60 * 1000;
109
110    /** GSM events */
111    protected static final int EVENT_RADIO_STATE_CHANGED               = 1;
112    protected static final int EVENT_NETWORK_STATE_CHANGED             = 2;
113    protected static final int EVENT_GET_SIGNAL_STRENGTH               = 3;
114    protected static final int EVENT_POLL_STATE_REGISTRATION           = 4;
115    protected static final int EVENT_POLL_STATE_GPRS                   = 5;
116    protected static final int EVENT_POLL_STATE_OPERATOR               = 6;
117    protected static final int EVENT_POLL_SIGNAL_STRENGTH              = 10;
118    protected static final int EVENT_NITZ_TIME                         = 11;
119    protected static final int EVENT_SIGNAL_STRENGTH_UPDATE            = 12;
120    protected static final int EVENT_RADIO_AVAILABLE                   = 13;
121    protected static final int EVENT_POLL_STATE_NETWORK_SELECTION_MODE = 14;
122    protected static final int EVENT_GET_LOC_DONE                      = 15;
123    protected static final int EVENT_SIM_RECORDS_LOADED                = 16;
124    protected static final int EVENT_SIM_READY                         = 17;
125    protected static final int EVENT_LOCATION_UPDATES_ENABLED          = 18;
126    protected static final int EVENT_GET_PREFERRED_NETWORK_TYPE        = 19;
127    protected static final int EVENT_SET_PREFERRED_NETWORK_TYPE        = 20;
128    protected static final int EVENT_RESET_PREFERRED_NETWORK_TYPE      = 21;
129    protected static final int EVENT_CHECK_REPORT_GPRS                 = 22;
130    protected static final int EVENT_RESTRICTED_STATE_CHANGED          = 23;
131
132    /** CDMA events */
133    protected static final int EVENT_POLL_STATE_REGISTRATION_CDMA      = 24;
134    protected static final int EVENT_POLL_STATE_OPERATOR_CDMA          = 25;
135    protected static final int EVENT_RUIM_READY                        = 26;
136    protected static final int EVENT_RUIM_RECORDS_LOADED               = 27;
137    protected static final int EVENT_POLL_SIGNAL_STRENGTH_CDMA         = 28;
138    protected static final int EVENT_GET_SIGNAL_STRENGTH_CDMA          = 29;
139    protected static final int EVENT_NETWORK_STATE_CHANGED_CDMA        = 30;
140    protected static final int EVENT_GET_LOC_DONE_CDMA                 = 31;
141    //protected static final int EVENT_UNUSED                            = 32;
142    protected static final int EVENT_NV_LOADED                         = 33;
143    protected static final int EVENT_POLL_STATE_CDMA_SUBSCRIPTION      = 34;
144    protected static final int EVENT_NV_READY                          = 35;
145    protected static final int EVENT_ERI_FILE_LOADED                   = 36;
146    protected static final int EVENT_OTA_PROVISION_STATUS_CHANGE       = 37;
147    protected static final int EVENT_SET_RADIO_POWER_OFF               = 38;
148    protected static final int EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED  = 39;
149    protected static final int EVENT_CDMA_PRL_VERSION_CHANGED          = 40;
150    protected static final int EVENT_RADIO_ON                          = 41;
151    protected static final int EVENT_ICC_CHANGED                       = 42;
152    protected static final int EVENT_GET_CELL_INFO_LIST                = 43;
153    protected static final int EVENT_UNSOL_CELL_INFO_LIST              = 44;
154
155    protected static final String TIMEZONE_PROPERTY = "persist.sys.timezone";
156
157    /**
158     * List of ISO codes for countries that can have an offset of
159     * GMT+0 when not in daylight savings time.  This ignores some
160     * small places such as the Canary Islands (Spain) and
161     * Danmarkshavn (Denmark).  The list must be sorted by code.
162    */
163    protected static final String[] GMT_COUNTRY_CODES = {
164        "bf", // Burkina Faso
165        "ci", // Cote d'Ivoire
166        "eh", // Western Sahara
167        "fo", // Faroe Islands, Denmark
168        "gb", // United Kingdom of Great Britain and Northern Ireland
169        "gh", // Ghana
170        "gm", // Gambia
171        "gn", // Guinea
172        "gw", // Guinea Bissau
173        "ie", // Ireland
174        "lr", // Liberia
175        "is", // Iceland
176        "ma", // Morocco
177        "ml", // Mali
178        "mr", // Mauritania
179        "pt", // Portugal
180        "sl", // Sierra Leone
181        "sn", // Senegal
182        "st", // Sao Tome and Principe
183        "tg", // Togo
184    };
185
186    private class CellInfoResult {
187        List<CellInfo> list;
188        Object lockObj = new Object();
189    }
190
191    /** Reason for registration denial. */
192    protected static final String REGISTRATION_DENIED_GEN  = "General";
193    protected static final String REGISTRATION_DENIED_AUTH = "Authentication Failure";
194
195    protected ServiceStateTracker(PhoneBase phoneBase, CommandsInterface ci, CellInfo cellInfo) {
196        mPhoneBase = phoneBase;
197        mCellInfo = cellInfo;
198        mCi = ci;
199        mUiccController = UiccController.getInstance();
200        mUiccController.registerForIccChanged(this, EVENT_ICC_CHANGED, null);
201        mCi.setOnSignalStrengthUpdate(this, EVENT_SIGNAL_STRENGTH_UPDATE, null);
202        mCi.registerForCellInfoList(this, EVENT_UNSOL_CELL_INFO_LIST, null);
203    }
204
205    public void dispose() {
206        mCi.unSetOnSignalStrengthUpdate(this);
207        mUiccController.unregisterForIccChanged(this);
208        mCi.unregisterForCellInfoList(this);
209    }
210
211    public boolean getDesiredPowerState() {
212        return mDesiredPowerState;
213    }
214
215    private SignalStrength mLastSignalStrength = null;
216    protected boolean notifySignalStrength() {
217        boolean notified = false;
218        synchronized(mCellInfo) {
219            if (!mSignalStrength.equals(mLastSignalStrength)) {
220                try {
221                    mPhoneBase.notifySignalStrength();
222                    notified = true;
223                } catch (NullPointerException ex) {
224                    loge("updateSignalStrength() Phone already destroyed: " + ex
225                            + "SignalStrength not notified");
226                }
227            }
228        }
229        return notified;
230    }
231
232    /**
233     * Registration point for combined roaming on
234     * combined roaming is true when roaming is true and ONS differs SPN
235     *
236     * @param h handler to notify
237     * @param what what code of message when delivered
238     * @param obj placed in Message.obj
239     */
240    public  void registerForRoamingOn(Handler h, int what, Object obj) {
241        Registrant r = new Registrant(h, what, obj);
242        mRoamingOnRegistrants.add(r);
243
244        if (mSS.getRoaming()) {
245            r.notifyRegistrant();
246        }
247    }
248
249    public  void unregisterForRoamingOn(Handler h) {
250        mRoamingOnRegistrants.remove(h);
251    }
252
253    /**
254     * Registration point for combined roaming off
255     * combined roaming is true when roaming is true and ONS differs SPN
256     *
257     * @param h handler to notify
258     * @param what what code of message when delivered
259     * @param obj placed in Message.obj
260     */
261    public  void registerForRoamingOff(Handler h, int what, Object obj) {
262        Registrant r = new Registrant(h, what, obj);
263        mRoamingOffRegistrants.add(r);
264
265        if (!mSS.getRoaming()) {
266            r.notifyRegistrant();
267        }
268    }
269
270    public  void unregisterForRoamingOff(Handler h) {
271        mRoamingOffRegistrants.remove(h);
272    }
273
274    /**
275     * Re-register network by toggling preferred network type.
276     * This is a work-around to deregister and register network since there is
277     * no ril api to set COPS=2 (deregister) only.
278     *
279     * @param onComplete is dispatched when this is complete.  it will be
280     * an AsyncResult, and onComplete.obj.exception will be non-null
281     * on failure.
282     */
283    public void reRegisterNetwork(Message onComplete) {
284        mCi.getPreferredNetworkType(
285                obtainMessage(EVENT_GET_PREFERRED_NETWORK_TYPE, onComplete));
286    }
287
288    public void
289    setRadioPower(boolean power) {
290        mDesiredPowerState = power;
291
292        setPowerStateToDesired();
293    }
294
295    /**
296     * These two flags manage the behavior of the cell lock -- the
297     * lock should be held if either flag is true.  The intention is
298     * to allow temporary acquisition of the lock to get a single
299     * update.  Such a lock grab and release can thus be made to not
300     * interfere with more permanent lock holds -- in other words, the
301     * lock will only be released if both flags are false, and so
302     * releases by temporary users will only affect the lock state if
303     * there is no continuous user.
304     */
305    private boolean mWantContinuousLocationUpdates;
306    private boolean mWantSingleLocationUpdate;
307
308    public void enableSingleLocationUpdate() {
309        if (mWantSingleLocationUpdate || mWantContinuousLocationUpdates) return;
310        mWantSingleLocationUpdate = true;
311        mCi.setLocationUpdates(true, obtainMessage(EVENT_LOCATION_UPDATES_ENABLED));
312    }
313
314    public void enableLocationUpdates() {
315        if (mWantSingleLocationUpdate || mWantContinuousLocationUpdates) return;
316        mWantContinuousLocationUpdates = true;
317        mCi.setLocationUpdates(true, obtainMessage(EVENT_LOCATION_UPDATES_ENABLED));
318    }
319
320    protected void disableSingleLocationUpdate() {
321        mWantSingleLocationUpdate = false;
322        if (!mWantSingleLocationUpdate && !mWantContinuousLocationUpdates) {
323            mCi.setLocationUpdates(false, null);
324        }
325    }
326
327    public void disableLocationUpdates() {
328        mWantContinuousLocationUpdates = false;
329        if (!mWantSingleLocationUpdate && !mWantContinuousLocationUpdates) {
330            mCi.setLocationUpdates(false, null);
331        }
332    }
333
334    @Override
335    public void handleMessage(Message msg) {
336        switch (msg.what) {
337            case EVENT_SET_RADIO_POWER_OFF:
338                synchronized(this) {
339                    if (mPendingRadioPowerOffAfterDataOff &&
340                            (msg.arg1 == mPendingRadioPowerOffAfterDataOffTag)) {
341                        if (DBG) log("EVENT_SET_RADIO_OFF, turn radio off now.");
342                        hangupAndPowerOff();
343                        mPendingRadioPowerOffAfterDataOffTag += 1;
344                        mPendingRadioPowerOffAfterDataOff = false;
345                    } else {
346                        log("EVENT_SET_RADIO_OFF is stale arg1=" + msg.arg1 +
347                                "!= tag=" + mPendingRadioPowerOffAfterDataOffTag);
348                    }
349                }
350                break;
351
352            case EVENT_ICC_CHANGED:
353                onUpdateIccAvailability();
354                break;
355
356            case EVENT_GET_CELL_INFO_LIST: {
357                AsyncResult ar = (AsyncResult) msg.obj;
358                CellInfoResult result = (CellInfoResult) ar.userObj;
359                synchronized(result.lockObj) {
360                    if (ar.exception != null) {
361                        log("EVENT_GET_CELL_INFO_LIST: error ret null, e=" + ar.exception);
362                        result.list = null;
363                    } else {
364                        result.list = (List<CellInfo>) ar.result;
365
366                        if (VDBG) {
367                            log("EVENT_GET_CELL_INFO_LIST: size=" + result.list.size()
368                                    + " list=" + result.list);
369                        }
370                    }
371                    mLastCellInfoList = result.list;
372                    result.lockObj.notify();
373                }
374                break;
375            }
376
377            case EVENT_UNSOL_CELL_INFO_LIST: {
378                AsyncResult ar = (AsyncResult) msg.obj;
379                if (ar.exception != null) {
380                    log("EVENT_UNSOL_CELL_INFO_LIST: error ignoring, e=" + ar.exception);
381                } else {
382                    List<CellInfo> list = (List<CellInfo>) ar.result;
383                    if (DBG) {
384                        log("EVENT_UNSOL_CELL_INFO_LIST: size=" + list.size()
385                                + " list=" + list);
386                    }
387                    mLastCellInfoList = list;
388                    mPhoneBase.notifyCellInfo(list);
389                }
390                break;
391            }
392
393            default:
394                log("Unhandled message with number: " + msg.what);
395                break;
396        }
397    }
398
399    protected abstract Phone getPhone();
400    protected abstract void handlePollStateResult(int what, AsyncResult ar);
401    protected abstract void updateSpnDisplay();
402    protected abstract void setPowerStateToDesired();
403    protected abstract void onUpdateIccAvailability();
404    protected abstract void log(String s);
405    protected abstract void loge(String s);
406
407    public abstract int getCurrentDataConnectionState();
408    public abstract boolean isConcurrentVoiceAndDataAllowed();
409
410    /**
411     * Registration point for transition into DataConnection attached.
412     * @param h handler to notify
413     * @param what what code of message when delivered
414     * @param obj placed in Message.obj
415     */
416    public void registerForDataConnectionAttached(Handler h, int what, Object obj) {
417        Registrant r = new Registrant(h, what, obj);
418        mAttachedRegistrants.add(r);
419
420        if (getCurrentDataConnectionState() == ServiceState.STATE_IN_SERVICE) {
421            r.notifyRegistrant();
422        }
423    }
424    public void unregisterForDataConnectionAttached(Handler h) {
425        mAttachedRegistrants.remove(h);
426    }
427
428    /**
429     * Registration point for transition into DataConnection detached.
430     * @param h handler to notify
431     * @param what what code of message when delivered
432     * @param obj placed in Message.obj
433     */
434    public void registerForDataConnectionDetached(Handler h, int what, Object obj) {
435        Registrant r = new Registrant(h, what, obj);
436        mDetachedRegistrants.add(r);
437
438        if (getCurrentDataConnectionState() != ServiceState.STATE_IN_SERVICE) {
439            r.notifyRegistrant();
440        }
441    }
442    public void unregisterForDataConnectionDetached(Handler h) {
443        mDetachedRegistrants.remove(h);
444    }
445
446    /**
447     * Registration point for transition into network attached.
448     * @param h handler to notify
449     * @param what what code of message when delivered
450     * @param obj in Message.obj
451     */
452    public void registerForNetworkAttached(Handler h, int what, Object obj) {
453        Registrant r = new Registrant(h, what, obj);
454
455        mNetworkAttachedRegistrants.add(r);
456        if (mSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE) {
457            r.notifyRegistrant();
458        }
459    }
460    public void unregisterForNetworkAttached(Handler h) {
461        mNetworkAttachedRegistrants.remove(h);
462    }
463
464    /**
465     * Registration point for transition into packet service restricted zone.
466     * @param h handler to notify
467     * @param what what code of message when delivered
468     * @param obj placed in Message.obj
469     */
470    public void registerForPsRestrictedEnabled(Handler h, int what, Object obj) {
471        Registrant r = new Registrant(h, what, obj);
472        mPsRestrictEnabledRegistrants.add(r);
473
474        if (mRestrictedState.isPsRestricted()) {
475            r.notifyRegistrant();
476        }
477    }
478
479    public void unregisterForPsRestrictedEnabled(Handler h) {
480        mPsRestrictEnabledRegistrants.remove(h);
481    }
482
483    /**
484     * Registration point for transition out of packet service restricted zone.
485     * @param h handler to notify
486     * @param what what code of message when delivered
487     * @param obj placed in Message.obj
488     */
489    public void registerForPsRestrictedDisabled(Handler h, int what, Object obj) {
490        Registrant r = new Registrant(h, what, obj);
491        mPsRestrictDisabledRegistrants.add(r);
492
493        if (mRestrictedState.isPsRestricted()) {
494            r.notifyRegistrant();
495        }
496    }
497
498    public void unregisterForPsRestrictedDisabled(Handler h) {
499        mPsRestrictDisabledRegistrants.remove(h);
500    }
501
502    /**
503     * Clean up existing voice and data connection then turn off radio power.
504     *
505     * Hang up the existing voice calls to decrease call drop rate.
506     */
507    public void powerOffRadioSafely(DcTrackerBase dcTracker) {
508        synchronized (this) {
509            if (!mPendingRadioPowerOffAfterDataOff) {
510                // To minimize race conditions we call cleanUpAllConnections on
511                // both if else paths instead of before this isDisconnected test.
512                if (dcTracker.isDisconnected()) {
513                    // To minimize race conditions we do this after isDisconnected
514                    dcTracker.cleanUpAllConnections(Phone.REASON_RADIO_TURNED_OFF);
515                    if (DBG) log("Data disconnected, turn off radio right away.");
516                    hangupAndPowerOff();
517                } else {
518                    dcTracker.cleanUpAllConnections(Phone.REASON_RADIO_TURNED_OFF);
519                    Message msg = Message.obtain(this);
520                    msg.what = EVENT_SET_RADIO_POWER_OFF;
521                    msg.arg1 = ++mPendingRadioPowerOffAfterDataOffTag;
522                    if (sendMessageDelayed(msg, 30000)) {
523                        if (DBG) log("Wait upto 30s for data to disconnect, then turn off radio.");
524                        mPendingRadioPowerOffAfterDataOff = true;
525                    } else {
526                        log("Cannot send delayed Msg, turn off radio right away.");
527                        hangupAndPowerOff();
528                    }
529                }
530            }
531        }
532    }
533
534    /**
535     * process the pending request to turn radio off after data is disconnected
536     *
537     * return true if there is pending request to process; false otherwise.
538     */
539    public boolean processPendingRadioPowerOffAfterDataOff() {
540        synchronized(this) {
541            if (mPendingRadioPowerOffAfterDataOff) {
542                if (DBG) log("Process pending request to turn radio off.");
543                mPendingRadioPowerOffAfterDataOffTag += 1;
544                hangupAndPowerOff();
545                mPendingRadioPowerOffAfterDataOff = false;
546                return true;
547            }
548            return false;
549        }
550    }
551
552    /**
553     * send signal-strength-changed notification if changed Called both for
554     * solicited and unsolicited signal strength updates
555     *
556     * @return true if the signal strength changed and a notification was sent.
557     */
558    protected boolean onSignalStrengthResult(AsyncResult ar, boolean isGsm) {
559        SignalStrength oldSignalStrength = mSignalStrength;
560
561        // This signal is used for both voice and data radio signal so parse
562        // all fields
563
564        if ((ar.exception == null) && (ar.result != null)) {
565            mSignalStrength = (SignalStrength) ar.result;
566            mSignalStrength.validateInput();
567            mSignalStrength.setGsm(isGsm);
568        } else {
569            log("onSignalStrengthResult() Exception from RIL : " + ar.exception);
570            mSignalStrength = new SignalStrength(isGsm);
571        }
572
573        return notifySignalStrength();
574    }
575
576    /**
577     * Hang up all voice call and turn off radio. Implemented by derived class.
578     */
579    protected abstract void hangupAndPowerOff();
580
581    /** Cancel a pending (if any) pollState() operation */
582    protected void cancelPollState() {
583        // This will effectively cancel the rest of the poll requests.
584        mPollingContext = new int[1];
585    }
586
587    /**
588     * Return true if time zone needs fixing.
589     *
590     * @param phoneBase
591     * @param operatorNumeric
592     * @param prevOperatorNumeric
593     * @param needToFixTimeZone
594     * @return true if time zone needs to be fixed
595     */
596    protected boolean shouldFixTimeZoneNow(PhoneBase phoneBase, String operatorNumeric,
597            String prevOperatorNumeric, boolean needToFixTimeZone) {
598        // Return false if the mcc isn't valid as we don't know where we are.
599        // Return true if we have an IccCard and the mcc changed or we
600        // need to fix it because when the NITZ time came in we didn't
601        // know the country code.
602
603        // If mcc is invalid then we'll return false
604        int mcc;
605        try {
606            mcc = Integer.parseInt(operatorNumeric.substring(0, 3));
607        } catch (Exception e) {
608            if (DBG) {
609                log("shouldFixTimeZoneNow: no mcc, operatorNumeric=" + operatorNumeric +
610                        " retVal=false");
611            }
612            return false;
613        }
614
615        // If prevMcc is invalid will make it different from mcc
616        // so we'll return true if the card exists.
617        int prevMcc;
618        try {
619            prevMcc = Integer.parseInt(prevOperatorNumeric.substring(0, 3));
620        } catch (Exception e) {
621            prevMcc = mcc + 1;
622        }
623
624        // Determine if the Icc card exists
625        boolean iccCardExist = false;
626        if (mUiccApplcation != null) {
627            iccCardExist = mUiccApplcation.getState() != AppState.APPSTATE_UNKNOWN;
628        }
629
630        // Determine retVal
631        boolean retVal = ((iccCardExist && (mcc != prevMcc)) || needToFixTimeZone);
632        if (DBG) {
633            long ctm = System.currentTimeMillis();
634            log("shouldFixTimeZoneNow: retVal=" + retVal +
635                    " iccCardExist=" + iccCardExist +
636                    " operatorNumeric=" + operatorNumeric + " mcc=" + mcc +
637                    " prevOperatorNumeric=" + prevOperatorNumeric + " prevMcc=" + prevMcc +
638                    " needToFixTimeZone=" + needToFixTimeZone +
639                    " ltod=" + TimeUtils.logTimeOfDay(ctm));
640        }
641        return retVal;
642    }
643
644    /**
645     * @return all available cell information or null if none.
646     */
647    public List<CellInfo> getAllCellInfo() {
648        CellInfoResult result = new CellInfoResult();
649        if (VDBG) log("SST.getAllCellInfo(): E");
650        int ver = mCi.getRilVersion();
651        if (ver >= 8) {
652            if (isCallerOnDifferentThread()) {
653                Message msg = obtainMessage(EVENT_GET_CELL_INFO_LIST, result);
654                synchronized(result.lockObj) {
655                    mCi.getCellInfoList(msg);
656                    try {
657                        result.lockObj.wait();
658                    } catch (InterruptedException e) {
659                        e.printStackTrace();
660                        result.list = null;
661                    }
662                }
663            } else {
664                log("SST.getAllCellInfo(): X return last, same thread probably RadioInfo");
665                result.list = mLastCellInfoList;
666            }
667        } else {
668            log("SST.getAllCellInfo(): X not implemented");
669            result.list = null;
670        }
671        if (DBG) {
672            if (result.list != null) {
673                log("SST.getAllCellInfo(): X size=" + result.list.size()
674                        + " list=" + result.list);
675            } else {
676                log("SST.getAllCellInfo(): X size=0 list=null");
677            }
678        }
679        return result.list;
680    }
681
682    /**
683     * @return signal strength
684     */
685    public SignalStrength getSignalStrength() {
686        synchronized(mCellInfo) {
687            return mSignalStrength;
688        }
689    }
690
691    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
692        pw.println("ServiceStateTracker:");
693        pw.println(" mSS=" + mSS);
694        pw.println(" mNewSS=" + mNewSS);
695        pw.println(" mCellInfo=" + mCellInfo);
696        pw.println(" mRestrictedState=" + mRestrictedState);
697        pw.println(" mPollingContext=" + mPollingContext);
698        pw.println(" mDesiredPowerState=" + mDesiredPowerState);
699        pw.println(" mDontPollSignalStrength=" + mDontPollSignalStrength);
700        pw.println(" mPendingRadioPowerOffAfterDataOff=" + mPendingRadioPowerOffAfterDataOff);
701        pw.println(" mPendingRadioPowerOffAfterDataOffTag=" + mPendingRadioPowerOffAfterDataOffTag);
702    }
703
704    /**
705     * Verifies the current thread is the same as the thread originally
706     * used in the initialization of this instance. Throws RuntimeException
707     * if not.
708     *
709     * @exception RuntimeException if the current thread is not
710     * the thread that originally obtained this PhoneBase instance.
711     */
712    protected void checkCorrectThread() {
713        if (Thread.currentThread() != getLooper().getThread()) {
714            throw new RuntimeException(
715                    "ServiceStateTracker must be used from within one thread");
716        }
717    }
718
719    protected boolean isCallerOnDifferentThread() {
720        boolean value = Thread.currentThread() != getLooper().getThread();
721        if (VDBG) log("isCallerOnDifferentThread: " + value);
722        return value;
723    }
724}
725