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