Home | History | Annotate | Download | only in telephony
      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;
     18 
     19 import android.os.AsyncResult;
     20 import android.os.Handler;
     21 import android.os.Message;
     22 import android.os.Registrant;
     23 import android.os.RegistrantList;
     24 import android.telephony.ServiceState;
     25 import android.telephony.SignalStrength;
     26 
     27 /**
     28  * {@hide}
     29  */
     30 public abstract class ServiceStateTracker extends Handler {
     31 
     32     protected CommandsInterface cm;
     33 
     34     public ServiceState ss;
     35     protected ServiceState newSS;
     36 
     37     public SignalStrength mSignalStrength;
     38 
     39     // TODO - this should not be public
     40     public RestrictedState mRestrictedState = new RestrictedState();
     41 
     42     /* The otaspMode passed to PhoneStateListener#onOtaspChanged */
     43     static public final int OTASP_UNINITIALIZED = 0;
     44     static public final int OTASP_UNKNOWN = 1;
     45     static public final int OTASP_NEEDED = 2;
     46     static public final int OTASP_NOT_NEEDED = 3;
     47 
     48     /**
     49      * A unique identifier to track requests associated with a poll
     50      * and ignore stale responses.  The value is a count-down of
     51      * expected responses in this pollingContext.
     52      */
     53     protected int[] pollingContext;
     54     protected boolean mDesiredPowerState;
     55 
     56     /**
     57      *  Values correspond to ServiceState.RADIO_TECHNOLOGY_ definitions.
     58      */
     59     protected int mRadioTechnology = 0;
     60     protected int mNewRadioTechnology = 0;
     61 
     62     /**
     63      * By default, strength polling is enabled.  However, if we're
     64      * getting unsolicited signal strength updates from the radio, set
     65      * value to true and don't bother polling any more.
     66      */
     67     protected boolean dontPollSignalStrength = false;
     68 
     69     protected RegistrantList mRoamingOnRegistrants = new RegistrantList();
     70     protected RegistrantList mRoamingOffRegistrants = new RegistrantList();
     71     protected RegistrantList mAttachedRegistrants = new RegistrantList();
     72     protected RegistrantList mDetachedRegistrants = new RegistrantList();
     73     protected RegistrantList mNetworkAttachedRegistrants = new RegistrantList();
     74     protected RegistrantList mPsRestrictEnabledRegistrants = new RegistrantList();
     75     protected RegistrantList mPsRestrictDisabledRegistrants = new RegistrantList();
     76 
     77     /* Radio power off pending flag and tag counter */
     78     private boolean mPendingRadioPowerOffAfterDataOff = false;
     79     private int mPendingRadioPowerOffAfterDataOffTag = 0;
     80 
     81     protected  static final boolean DBG = true;
     82 
     83     /** Signal strength poll rate. */
     84     protected static final int POLL_PERIOD_MILLIS = 20 * 1000;
     85 
     86     /** Waiting period before recheck gprs and voice registration. */
     87     public static final int DEFAULT_GPRS_CHECK_PERIOD_MILLIS = 60 * 1000;
     88 
     89     /** GSM events */
     90     protected static final int EVENT_RADIO_STATE_CHANGED               = 1;
     91     protected static final int EVENT_NETWORK_STATE_CHANGED             = 2;
     92     protected static final int EVENT_GET_SIGNAL_STRENGTH               = 3;
     93     protected static final int EVENT_POLL_STATE_REGISTRATION           = 4;
     94     protected static final int EVENT_POLL_STATE_GPRS                   = 5;
     95     protected static final int EVENT_POLL_STATE_OPERATOR               = 6;
     96     protected static final int EVENT_POLL_SIGNAL_STRENGTH              = 10;
     97     protected static final int EVENT_NITZ_TIME                         = 11;
     98     protected static final int EVENT_SIGNAL_STRENGTH_UPDATE            = 12;
     99     protected static final int EVENT_RADIO_AVAILABLE                   = 13;
    100     protected static final int EVENT_POLL_STATE_NETWORK_SELECTION_MODE = 14;
    101     protected static final int EVENT_GET_LOC_DONE                      = 15;
    102     protected static final int EVENT_SIM_RECORDS_LOADED                = 16;
    103     protected static final int EVENT_SIM_READY                         = 17;
    104     protected static final int EVENT_LOCATION_UPDATES_ENABLED          = 18;
    105     protected static final int EVENT_GET_PREFERRED_NETWORK_TYPE        = 19;
    106     protected static final int EVENT_SET_PREFERRED_NETWORK_TYPE        = 20;
    107     protected static final int EVENT_RESET_PREFERRED_NETWORK_TYPE      = 21;
    108     protected static final int EVENT_CHECK_REPORT_GPRS                 = 22;
    109     protected static final int EVENT_RESTRICTED_STATE_CHANGED          = 23;
    110 
    111     /** CDMA events */
    112     protected static final int EVENT_POLL_STATE_REGISTRATION_CDMA      = 24;
    113     protected static final int EVENT_POLL_STATE_OPERATOR_CDMA          = 25;
    114     protected static final int EVENT_RUIM_READY                        = 26;
    115     protected static final int EVENT_RUIM_RECORDS_LOADED               = 27;
    116     protected static final int EVENT_POLL_SIGNAL_STRENGTH_CDMA         = 28;
    117     protected static final int EVENT_GET_SIGNAL_STRENGTH_CDMA          = 29;
    118     protected static final int EVENT_NETWORK_STATE_CHANGED_CDMA        = 30;
    119     protected static final int EVENT_GET_LOC_DONE_CDMA                 = 31;
    120     protected static final int EVENT_SIGNAL_STRENGTH_UPDATE_CDMA       = 32;
    121     protected static final int EVENT_NV_LOADED                         = 33;
    122     protected static final int EVENT_POLL_STATE_CDMA_SUBSCRIPTION      = 34;
    123     protected static final int EVENT_NV_READY                          = 35;
    124     protected static final int EVENT_ERI_FILE_LOADED                   = 36;
    125     protected static final int EVENT_OTA_PROVISION_STATUS_CHANGE       = 37;
    126     protected static final int EVENT_SET_RADIO_POWER_OFF               = 38;
    127 
    128     protected static final String TIMEZONE_PROPERTY = "persist.sys.timezone";
    129 
    130     /**
    131      * List of ISO codes for countries that can have an offset of
    132      * GMT+0 when not in daylight savings time.  This ignores some
    133      * small places such as the Canary Islands (Spain) and
    134      * Danmarkshavn (Denmark).  The list must be sorted by code.
    135     */
    136     protected static final String[] GMT_COUNTRY_CODES = {
    137         "bf", // Burkina Faso
    138         "ci", // Cote d'Ivoire
    139         "eh", // Western Sahara
    140         "fo", // Faroe Islands, Denmark
    141         "gh", // Ghana
    142         "gm", // Gambia
    143         "gn", // Guinea
    144         "gw", // Guinea Bissau
    145         "ie", // Ireland
    146         "lr", // Liberia
    147         "is", // Iceland
    148         "ma", // Morocco
    149         "ml", // Mali
    150         "mr", // Mauritania
    151         "pt", // Portugal
    152         "sl", // Sierra Leone
    153         "sn", // Senegal
    154         "st", // Sao Tome and Principe
    155         "tg", // Togo
    156         "uk", // U.K
    157     };
    158 
    159     /** Reason for registration denial. */
    160     protected static final String REGISTRATION_DENIED_GEN  = "General";
    161     protected static final String REGISTRATION_DENIED_AUTH = "Authentication Failure";
    162 
    163     public ServiceStateTracker() {
    164     }
    165 
    166     public boolean getDesiredPowerState() {
    167         return mDesiredPowerState;
    168     }
    169 
    170     /**
    171      * Registration point for combined roaming on
    172      * combined roaming is true when roaming is true and ONS differs SPN
    173      *
    174      * @param h handler to notify
    175      * @param what what code of message when delivered
    176      * @param obj placed in Message.obj
    177      */
    178     public  void registerForRoamingOn(Handler h, int what, Object obj) {
    179         Registrant r = new Registrant(h, what, obj);
    180         mRoamingOnRegistrants.add(r);
    181 
    182         if (ss.getRoaming()) {
    183             r.notifyRegistrant();
    184         }
    185     }
    186 
    187     public  void unregisterForRoamingOn(Handler h) {
    188         mRoamingOnRegistrants.remove(h);
    189     }
    190 
    191     /**
    192      * Registration point for combined roaming off
    193      * combined roaming is true when roaming is true and ONS differs SPN
    194      *
    195      * @param h handler to notify
    196      * @param what what code of message when delivered
    197      * @param obj placed in Message.obj
    198      */
    199     public  void registerForRoamingOff(Handler h, int what, Object obj) {
    200         Registrant r = new Registrant(h, what, obj);
    201         mRoamingOffRegistrants.add(r);
    202 
    203         if (!ss.getRoaming()) {
    204             r.notifyRegistrant();
    205         }
    206     }
    207 
    208     public  void unregisterForRoamingOff(Handler h) {
    209         mRoamingOffRegistrants.remove(h);
    210     }
    211 
    212     /**
    213      * Re-register network by toggling preferred network type.
    214      * This is a work-around to deregister and register network since there is
    215      * no ril api to set COPS=2 (deregister) only.
    216      *
    217      * @param onComplete is dispatched when this is complete.  it will be
    218      * an AsyncResult, and onComplete.obj.exception will be non-null
    219      * on failure.
    220      */
    221     public void reRegisterNetwork(Message onComplete) {
    222         cm.getPreferredNetworkType(
    223                 obtainMessage(EVENT_GET_PREFERRED_NETWORK_TYPE, onComplete));
    224     }
    225 
    226     public void
    227     setRadioPower(boolean power) {
    228         mDesiredPowerState = power;
    229 
    230         setPowerStateToDesired();
    231     }
    232 
    233     /**
    234      * These two flags manage the behavior of the cell lock -- the
    235      * lock should be held if either flag is true.  The intention is
    236      * to allow temporary acquisition of the lock to get a single
    237      * update.  Such a lock grab and release can thus be made to not
    238      * interfere with more permanent lock holds -- in other words, the
    239      * lock will only be released if both flags are false, and so
    240      * releases by temporary users will only affect the lock state if
    241      * there is no continuous user.
    242      */
    243     private boolean mWantContinuousLocationUpdates;
    244     private boolean mWantSingleLocationUpdate;
    245 
    246     public void enableSingleLocationUpdate() {
    247         if (mWantSingleLocationUpdate || mWantContinuousLocationUpdates) return;
    248         mWantSingleLocationUpdate = true;
    249         cm.setLocationUpdates(true, obtainMessage(EVENT_LOCATION_UPDATES_ENABLED));
    250     }
    251 
    252     public void enableLocationUpdates() {
    253         if (mWantSingleLocationUpdate || mWantContinuousLocationUpdates) return;
    254         mWantContinuousLocationUpdates = true;
    255         cm.setLocationUpdates(true, obtainMessage(EVENT_LOCATION_UPDATES_ENABLED));
    256     }
    257 
    258     protected void disableSingleLocationUpdate() {
    259         mWantSingleLocationUpdate = false;
    260         if (!mWantSingleLocationUpdate && !mWantContinuousLocationUpdates) {
    261             cm.setLocationUpdates(false, null);
    262         }
    263     }
    264 
    265     public void disableLocationUpdates() {
    266         mWantContinuousLocationUpdates = false;
    267         if (!mWantSingleLocationUpdate && !mWantContinuousLocationUpdates) {
    268             cm.setLocationUpdates(false, null);
    269         }
    270     }
    271 
    272     @Override
    273     public void handleMessage(Message msg) {
    274         switch (msg.what) {
    275             case EVENT_SET_RADIO_POWER_OFF:
    276                 synchronized(this) {
    277                     if (mPendingRadioPowerOffAfterDataOff &&
    278                             (msg.arg1 == mPendingRadioPowerOffAfterDataOffTag)) {
    279                         if (DBG) log("EVENT_SET_RADIO_OFF, turn radio off now.");
    280                         hangupAndPowerOff();
    281                         mPendingRadioPowerOffAfterDataOffTag += 1;
    282                         mPendingRadioPowerOffAfterDataOff = false;
    283                     } else {
    284                         log("EVENT_SET_RADIO_OFF is stale arg1=" + msg.arg1 +
    285                                 "!= tag=" + mPendingRadioPowerOffAfterDataOffTag);
    286                     }
    287                 }
    288                 break;
    289 
    290             default:
    291                 log("Unhandled message with number: " + msg.what);
    292                 break;
    293         }
    294     }
    295 
    296     protected abstract Phone getPhone();
    297     protected abstract void handlePollStateResult(int what, AsyncResult ar);
    298     protected abstract void updateSpnDisplay();
    299     protected abstract void setPowerStateToDesired();
    300     protected abstract void log(String s);
    301     protected abstract void loge(String s);
    302 
    303     public abstract int getCurrentDataConnectionState();
    304     public abstract boolean isConcurrentVoiceAndDataAllowed();
    305 
    306     /**
    307      * Registration point for transition into DataConnection attached.
    308      * @param h handler to notify
    309      * @param what what code of message when delivered
    310      * @param obj placed in Message.obj
    311      */
    312     public void registerForDataConnectionAttached(Handler h, int what, Object obj) {
    313         Registrant r = new Registrant(h, what, obj);
    314         mAttachedRegistrants.add(r);
    315 
    316         if (getCurrentDataConnectionState() == ServiceState.STATE_IN_SERVICE) {
    317             r.notifyRegistrant();
    318         }
    319     }
    320     public void unregisterForDataConnectionAttached(Handler h) {
    321         mAttachedRegistrants.remove(h);
    322     }
    323 
    324     /**
    325      * Registration point for transition into DataConnection detached.
    326      * @param h handler to notify
    327      * @param what what code of message when delivered
    328      * @param obj placed in Message.obj
    329      */
    330     public void registerForDataConnectionDetached(Handler h, int what, Object obj) {
    331         Registrant r = new Registrant(h, what, obj);
    332         mDetachedRegistrants.add(r);
    333 
    334         if (getCurrentDataConnectionState() != ServiceState.STATE_IN_SERVICE) {
    335             r.notifyRegistrant();
    336         }
    337     }
    338     public void unregisterForDataConnectionDetached(Handler h) {
    339         mDetachedRegistrants.remove(h);
    340     }
    341 
    342     /**
    343      * Registration point for transition into network attached.
    344      * @param h handler to notify
    345      * @param what what code of message when delivered
    346      * @param obj in Message.obj
    347      */
    348     public void registerForNetworkAttached(Handler h, int what, Object obj) {
    349         Registrant r = new Registrant(h, what, obj);
    350 
    351         mNetworkAttachedRegistrants.add(r);
    352         if (ss.getState() == ServiceState.STATE_IN_SERVICE) {
    353             r.notifyRegistrant();
    354         }
    355     }
    356     public void unregisterForNetworkAttached(Handler h) {
    357         mNetworkAttachedRegistrants.remove(h);
    358     }
    359 
    360     /**
    361      * Registration point for transition into packet service restricted zone.
    362      * @param h handler to notify
    363      * @param what what code of message when delivered
    364      * @param obj placed in Message.obj
    365      */
    366     public void registerForPsRestrictedEnabled(Handler h, int what, Object obj) {
    367         Registrant r = new Registrant(h, what, obj);
    368         mPsRestrictEnabledRegistrants.add(r);
    369 
    370         if (mRestrictedState.isPsRestricted()) {
    371             r.notifyRegistrant();
    372         }
    373     }
    374 
    375     public void unregisterForPsRestrictedEnabled(Handler h) {
    376         mPsRestrictEnabledRegistrants.remove(h);
    377     }
    378 
    379     /**
    380      * Registration point for transition out of packet service restricted zone.
    381      * @param h handler to notify
    382      * @param what what code of message when delivered
    383      * @param obj placed in Message.obj
    384      */
    385     public void registerForPsRestrictedDisabled(Handler h, int what, Object obj) {
    386         Registrant r = new Registrant(h, what, obj);
    387         mPsRestrictDisabledRegistrants.add(r);
    388 
    389         if (mRestrictedState.isPsRestricted()) {
    390             r.notifyRegistrant();
    391         }
    392     }
    393 
    394     public void unregisterForPsRestrictedDisabled(Handler h) {
    395         mPsRestrictDisabledRegistrants.remove(h);
    396     }
    397 
    398     /**
    399      * Clean up existing voice and data connection then turn off radio power.
    400      *
    401      * Hang up the existing voice calls to decrease call drop rate.
    402      */
    403     public void powerOffRadioSafely(DataConnectionTracker dcTracker) {
    404         synchronized (this) {
    405             if (!mPendingRadioPowerOffAfterDataOff) {
    406                 // To minimize race conditions we call cleanUpAllConnections on
    407                 // both if else paths instead of before this isDisconnected test.
    408                 if (dcTracker.isDisconnected()) {
    409                     // To minimize race conditions we do this after isDisconnected
    410                     dcTracker.cleanUpAllConnections(Phone.REASON_RADIO_TURNED_OFF);
    411                     if (DBG) log("Data disconnected, turn off radio right away.");
    412                     hangupAndPowerOff();
    413                 } else {
    414                     dcTracker.cleanUpAllConnections(Phone.REASON_RADIO_TURNED_OFF);
    415                     Message msg = Message.obtain(this);
    416                     msg.what = EVENT_SET_RADIO_POWER_OFF;
    417                     msg.arg1 = ++mPendingRadioPowerOffAfterDataOffTag;
    418                     if (sendMessageDelayed(msg, 30000)) {
    419                         if (DBG) log("Wait upto 30s for data to disconnect, then turn off radio.");
    420                         mPendingRadioPowerOffAfterDataOff = true;
    421                     } else {
    422                         log("Cannot send delayed Msg, turn off radio right away.");
    423                         hangupAndPowerOff();
    424                     }
    425                 }
    426             }
    427         }
    428     }
    429 
    430     /**
    431      * process the pending request to turn radio off after data is disconnected
    432      *
    433      * return true if there is pending request to process; false otherwise.
    434      */
    435     public boolean processPendingRadioPowerOffAfterDataOff() {
    436         synchronized(this) {
    437             if (mPendingRadioPowerOffAfterDataOff) {
    438                 if (DBG) log("Process pending request to turn radio off.");
    439                 mPendingRadioPowerOffAfterDataOffTag += 1;
    440                 hangupAndPowerOff();
    441                 mPendingRadioPowerOffAfterDataOff = false;
    442                 return true;
    443             }
    444             return false;
    445         }
    446     }
    447 
    448     /**
    449      * Hang up all voice call and turn off radio. Implemented by derived class.
    450      */
    451     protected abstract void hangupAndPowerOff();
    452 
    453     /** Cancel a pending (if any) pollState() operation */
    454     protected void cancelPollState() {
    455         // This will effectively cancel the rest of the poll requests.
    456         pollingContext = new int[1];
    457     }
    458 }
    459