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.app.PendingIntent;
     20 import android.content.BroadcastReceiver;
     21 import android.content.ContentResolver;
     22 import android.content.Context;
     23 import android.content.Intent;
     24 import android.content.IntentFilter;
     25 import android.content.SharedPreferences;
     26 import android.database.ContentObserver;
     27 import android.net.LinkCapabilities;
     28 import android.net.LinkProperties;
     29 import android.net.NetworkInfo;
     30 import android.net.TrafficStats;
     31 import android.net.wifi.WifiManager;
     32 import android.os.AsyncResult;
     33 import android.os.Bundle;
     34 import android.os.Handler;
     35 import android.os.Message;
     36 import android.os.Messenger;
     37 import android.os.SystemClock;
     38 import android.os.SystemProperties;
     39 import android.preference.PreferenceManager;
     40 import android.provider.Settings;
     41 import android.provider.Settings.SettingNotFoundException;
     42 import android.telephony.ServiceState;
     43 import android.text.TextUtils;
     44 import android.util.Log;
     45 
     46 import com.android.internal.R;
     47 import com.android.internal.telephony.DataConnection.FailCause;
     48 import com.android.internal.util.AsyncChannel;
     49 import com.android.internal.util.Protocol;
     50 
     51 import java.util.ArrayList;
     52 import java.util.HashMap;
     53 import java.util.concurrent.ConcurrentHashMap;
     54 import java.util.concurrent.atomic.AtomicInteger;
     55 
     56 /**
     57  * {@hide}
     58  */
     59 public abstract class DataConnectionTracker extends Handler {
     60     protected static final boolean DBG = true;
     61     protected static final boolean VDBG = false;
     62 
     63     /**
     64      * IDLE: ready to start data connection setup, default state
     65      * INITING: state of issued setupDefaultPDP() but not finish yet
     66      * CONNECTING: state of issued startPppd() but not finish yet
     67      * SCANNING: data connection fails with one apn but other apns are available
     68      *           ready to start data connection on other apns (before INITING)
     69      * CONNECTED: IP connection is setup
     70      * DISCONNECTING: Connection.disconnect() has been called, but PDP
     71      *                context is not yet deactivated
     72      * FAILED: data connection fail for all apns settings
     73      *
     74      * getDataConnectionState() maps State to DataState
     75      *      FAILED or IDLE : DISCONNECTED
     76      *      INITING or CONNECTING or SCANNING: CONNECTING
     77      *      CONNECTED : CONNECTED or DISCONNECTING
     78      */
     79     public enum State {
     80         IDLE,
     81         INITING,
     82         CONNECTING,
     83         SCANNING,
     84         CONNECTED,
     85         DISCONNECTING,
     86         FAILED
     87     }
     88 
     89     public enum Activity {
     90         NONE,
     91         DATAIN,
     92         DATAOUT,
     93         DATAINANDOUT,
     94         DORMANT
     95     }
     96 
     97     public static String ACTION_DATA_CONNECTION_TRACKER_MESSENGER =
     98         "com.android.internal.telephony";
     99     public static String EXTRA_MESSENGER = "EXTRA_MESSENGER";
    100 
    101     /***** Event Codes *****/
    102     protected static final int BASE = Protocol.BASE_DATA_CONNECTION_TRACKER;
    103     protected static final int EVENT_DATA_SETUP_COMPLETE = BASE + 0;
    104     protected static final int EVENT_RADIO_AVAILABLE = BASE + 1;
    105     protected static final int EVENT_RECORDS_LOADED = BASE + 2;
    106     protected static final int EVENT_TRY_SETUP_DATA = BASE + 3;
    107     protected static final int EVENT_DATA_STATE_CHANGED = BASE + 4;
    108     protected static final int EVENT_POLL_PDP = BASE + 5;
    109     protected static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = BASE + 6;
    110     protected static final int EVENT_VOICE_CALL_STARTED = BASE + 7;
    111     protected static final int EVENT_VOICE_CALL_ENDED = BASE + 8;
    112     protected static final int EVENT_DATA_CONNECTION_DETACHED = BASE + 9;
    113     protected static final int EVENT_LINK_STATE_CHANGED = BASE + 10;
    114     protected static final int EVENT_ROAMING_ON = BASE + 11;
    115     protected static final int EVENT_ROAMING_OFF = BASE + 12;
    116     protected static final int EVENT_ENABLE_NEW_APN = BASE + 13;
    117     protected static final int EVENT_RESTORE_DEFAULT_APN = BASE + 14;
    118     protected static final int EVENT_DISCONNECT_DONE = BASE + 15;
    119     protected static final int EVENT_DATA_CONNECTION_ATTACHED = BASE + 16;
    120     protected static final int EVENT_DATA_STALL_ALARM = BASE + 17;
    121     protected static final int EVENT_DO_RECOVERY = BASE + 18;
    122     protected static final int EVENT_APN_CHANGED = BASE + 19;
    123     protected static final int EVENT_CDMA_DATA_DETACHED = BASE + 20;
    124     protected static final int EVENT_NV_READY = BASE + 21;
    125     protected static final int EVENT_PS_RESTRICT_ENABLED = BASE + 22;
    126     protected static final int EVENT_PS_RESTRICT_DISABLED = BASE + 23;
    127     public static final int EVENT_CLEAN_UP_CONNECTION = BASE + 24;
    128     protected static final int EVENT_CDMA_OTA_PROVISION = BASE + 25;
    129     protected static final int EVENT_RESTART_RADIO = BASE + 26;
    130     protected static final int EVENT_SET_INTERNAL_DATA_ENABLE = BASE + 27;
    131     protected static final int EVENT_RESET_DONE = BASE + 28;
    132     public static final int CMD_SET_USER_DATA_ENABLE = BASE + 29;
    133     public static final int EVENT_CLEAN_UP_ALL_CONNECTIONS = BASE + 30;
    134     public static final int CMD_SET_DEPENDENCY_MET = BASE + 31;
    135     public static final int CMD_SET_POLICY_DATA_ENABLE = BASE + 32;
    136 
    137     /***** Constants *****/
    138 
    139     protected static final int APN_INVALID_ID = -1;
    140     protected static final int APN_DEFAULT_ID = 0;
    141     protected static final int APN_MMS_ID = 1;
    142     protected static final int APN_SUPL_ID = 2;
    143     protected static final int APN_DUN_ID = 3;
    144     protected static final int APN_HIPRI_ID = 4;
    145     protected static final int APN_IMS_ID = 5;
    146     protected static final int APN_FOTA_ID = 6;
    147     protected static final int APN_CBS_ID = 7;
    148     protected static final int APN_NUM_TYPES = 8;
    149 
    150     public static final int DISABLED = 0;
    151     public static final int ENABLED = 1;
    152 
    153     public static final String APN_TYPE_KEY = "apnType";
    154 
    155     /** Delay between APN attempts.
    156         Note the property override mechanism is there just for testing purpose only. */
    157     protected static final int APN_DELAY_MILLIS =
    158                                 SystemProperties.getInt("persist.radio.apn_delay", 5000);
    159 
    160     protected Object mDataEnabledLock = new Object();
    161 
    162     // responds to the setInternalDataEnabled call - used internally to turn off data
    163     // for example during emergency calls
    164     protected boolean mInternalDataEnabled = true;
    165 
    166     // responds to public (user) API to enable/disable data use
    167     // independent of mInternalDataEnabled and requests for APN access
    168     // persisted
    169     protected boolean mUserDataEnabled = true;
    170 
    171     // TODO: move away from static state once 5587429 is fixed.
    172     protected static boolean sPolicyDataEnabled = true;
    173 
    174     private boolean[] dataEnabled = new boolean[APN_NUM_TYPES];
    175 
    176     private int enabledCount = 0;
    177 
    178     /* Currently requested APN type (TODO: This should probably be a parameter not a member) */
    179     protected String mRequestedApnType = Phone.APN_TYPE_DEFAULT;
    180 
    181     /** Retry configuration: A doubling of retry times from 5secs to 30minutes */
    182     protected static final String DEFAULT_DATA_RETRY_CONFIG = "default_randomization=2000,"
    183         + "5000,10000,20000,40000,80000:5000,160000:5000,"
    184         + "320000:5000,640000:5000,1280000:5000,1800000:5000";
    185 
    186     /** Retry configuration for secondary networks: 4 tries in 20 sec */
    187     protected static final String SECONDARY_DATA_RETRY_CONFIG =
    188             "max_retries=3, 5000, 5000, 5000";
    189 
    190     /** Slow poll when attempting connection recovery. */
    191     protected static final int POLL_NETSTAT_SLOW_MILLIS = 5000;
    192     /** Default max failure count before attempting to network re-registration. */
    193     protected static final int DEFAULT_MAX_PDP_RESET_FAIL = 3;
    194 
    195     /**
    196      * After detecting a potential connection problem, this is the max number
    197      * of subsequent polls before attempting recovery.
    198      */
    199     protected static final int NO_RECV_POLL_LIMIT = 24;
    200     // 1 sec. default polling interval when screen is on.
    201     protected static final int POLL_NETSTAT_MILLIS = 1000;
    202     // 10 min. default polling interval when screen is off.
    203     protected static final int POLL_NETSTAT_SCREEN_OFF_MILLIS = 1000*60*10;
    204     // 2 min for round trip time
    205     protected static final int POLL_LONGEST_RTT = 120 * 1000;
    206     // Default sent packets without ack which triggers initial recovery steps
    207     protected static final int NUMBER_SENT_PACKETS_OF_HANG = 10;
    208     // how long to wait before switching back to default APN
    209     protected static final int RESTORE_DEFAULT_APN_DELAY = 1 * 60 * 1000;
    210     // system property that can override the above value
    211     protected static final String APN_RESTORE_DELAY_PROP_NAME = "android.telephony.apn-restore";
    212     // represents an invalid IP address
    213     protected static final String NULL_IP = "0.0.0.0";
    214 
    215     // Default for the data stall alarm while non-aggressive stall detection
    216     protected static final int DATA_STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS_DEFAULT = 1000 * 60 * 6;
    217     // Default for the data stall alarm for aggressive stall detection
    218     protected static final int DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS_DEFAULT = 1000 * 60;
    219     // If attempt is less than this value we're doing first level recovery
    220     protected static final int DATA_STALL_NO_RECV_POLL_LIMIT = 1;
    221     // Tag for tracking stale alarms
    222     protected static final String DATA_STALL_ALARM_TAG_EXTRA = "data.stall.alram.tag";
    223 
    224     // TODO: See if we can remove INTENT_RECONNECT_ALARM
    225     //       having to have different values for GSM and
    226     //       CDMA. If so we can then remove the need for
    227     //       getActionIntentReconnectAlarm.
    228     protected static final String INTENT_RECONNECT_ALARM_EXTRA_REASON = "reason";
    229 
    230     // Used for debugging. Send the INTENT with an optional counter value with the number
    231     // of times the setup is to fail before succeeding. If the counter isn't passed the
    232     // setup will fail once. Example fail two times with FailCause.SIGNAL_LOST(-3)
    233     // adb shell am broadcast \
    234     //  -a com.android.internal.telephony.dataconnectiontracker.intent_set_fail_data_setup_counter \
    235     //  --ei fail_data_setup_counter 3 --ei fail_data_setup_fail_cause -3
    236     protected static final String INTENT_SET_FAIL_DATA_SETUP_COUNTER =
    237         "com.android.internal.telephony.dataconnectiontracker.intent_set_fail_data_setup_counter";
    238     protected static final String FAIL_DATA_SETUP_COUNTER = "fail_data_setup_counter";
    239     protected int mFailDataSetupCounter = 0;
    240     protected static final String FAIL_DATA_SETUP_FAIL_CAUSE = "fail_data_setup_fail_cause";
    241     protected FailCause mFailDataSetupFailCause = FailCause.ERROR_UNSPECIFIED;
    242 
    243     protected static final String DEFALUT_DATA_ON_BOOT_PROP = "net.def_data_on_boot";
    244 
    245     // member variables
    246     protected PhoneBase mPhone;
    247     protected Activity mActivity = Activity.NONE;
    248     protected State mState = State.IDLE;
    249     protected Handler mDataConnectionTracker = null;
    250 
    251 
    252     protected long mTxPkts;
    253     protected long mRxPkts;
    254     protected int mNetStatPollPeriod;
    255     protected boolean mNetStatPollEnabled = false;
    256 
    257     protected TxRxSum mDataStallTxRxSum = new TxRxSum(0, 0);
    258     // Used to track stale data stall alarms.
    259     protected int mDataStallAlarmTag = (int) SystemClock.elapsedRealtime();
    260     // The current data stall alarm intent
    261     protected PendingIntent mDataStallAlarmIntent = null;
    262     // Number of packets sent since the last received packet
    263     protected long mSentSinceLastRecv;
    264     // Controls when a simple recovery attempt it to be tried
    265     protected int mNoRecvPollCount = 0;
    266 
    267     // wifi connection status will be updated by sticky intent
    268     protected boolean mIsWifiConnected = false;
    269 
    270     /** Intent sent when the reconnect alarm fires. */
    271     protected PendingIntent mReconnectIntent = null;
    272 
    273     /** CID of active data connection */
    274     protected int mCidActive;
    275 
    276     // When false we will not auto attach and manually attaching is required.
    277     protected boolean mAutoAttachOnCreation = false;
    278 
    279     // State of screen
    280     // (TODO: Reconsider tying directly to screen, maybe this is
    281     //        really a lower power mode")
    282     protected boolean mIsScreenOn = true;
    283 
    284     /** Allows the generation of unique Id's for DataConnection objects */
    285     protected AtomicInteger mUniqueIdGenerator = new AtomicInteger(0);
    286 
    287     /** The data connections. */
    288     protected HashMap<Integer, DataConnection> mDataConnections =
    289         new HashMap<Integer, DataConnection>();
    290 
    291     /** The data connection async channels */
    292     protected HashMap<Integer, DataConnectionAc> mDataConnectionAsyncChannels =
    293         new HashMap<Integer, DataConnectionAc>();
    294 
    295     /** Convert an ApnType string to Id (TODO: Use "enumeration" instead of String for ApnType) */
    296     protected HashMap<String, Integer> mApnToDataConnectionId =
    297                                     new HashMap<String, Integer>();
    298 
    299     /** Phone.APN_TYPE_* ===> ApnContext */
    300     protected ConcurrentHashMap<String, ApnContext> mApnContexts;
    301 
    302     /* Currently active APN */
    303     protected ApnSetting mActiveApn;
    304 
    305     /** allApns holds all apns */
    306     protected ArrayList<ApnSetting> mAllApns = null;
    307 
    308     /** preferred apn */
    309     protected ApnSetting mPreferredApn = null;
    310 
    311     /** Is packet service restricted by network */
    312     protected boolean mIsPsRestricted = false;
    313 
    314     /* Once disposed dont handle any messages */
    315     protected boolean mIsDisposed = false;
    316 
    317     protected BroadcastReceiver mIntentReceiver = new BroadcastReceiver ()
    318     {
    319         @Override
    320         public void onReceive(Context context, Intent intent)
    321         {
    322             String action = intent.getAction();
    323             if (DBG) log("onReceive: action=" + action);
    324             if (action.equals(Intent.ACTION_SCREEN_ON)) {
    325                 mIsScreenOn = true;
    326                 stopNetStatPoll();
    327                 startNetStatPoll();
    328                 restartDataStallAlarm();
    329             } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
    330                 mIsScreenOn = false;
    331                 stopNetStatPoll();
    332                 startNetStatPoll();
    333                 restartDataStallAlarm();
    334             } else if (action.startsWith(getActionIntentReconnectAlarm())) {
    335                 log("Reconnect alarm. Previous state was " + mState);
    336                 onActionIntentReconnectAlarm(intent);
    337             } else if (action.equals(getActionIntentDataStallAlarm())) {
    338                 onActionIntentDataStallAlarm(intent);
    339             } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
    340                 final android.net.NetworkInfo networkInfo = (NetworkInfo)
    341                         intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
    342                 mIsWifiConnected = (networkInfo != null && networkInfo.isConnected());
    343             } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
    344                 final boolean enabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
    345                         WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED;
    346 
    347                 if (!enabled) {
    348                     // when WiFi got disabled, the NETWORK_STATE_CHANGED_ACTION
    349                     // quit and won't report disconnected until next enabling.
    350                     mIsWifiConnected = false;
    351                 }
    352             } else if (action.equals(INTENT_SET_FAIL_DATA_SETUP_COUNTER)) {
    353                 mFailDataSetupCounter = intent.getIntExtra(FAIL_DATA_SETUP_COUNTER, 1);
    354                 mFailDataSetupFailCause = FailCause.fromInt(
    355                         intent.getIntExtra(FAIL_DATA_SETUP_FAIL_CAUSE,
    356                                                     FailCause.ERROR_UNSPECIFIED.getErrorCode()));
    357                 if (DBG) log("set mFailDataSetupCounter=" + mFailDataSetupCounter +
    358                         " mFailDataSetupFailCause=" + mFailDataSetupFailCause);
    359             }
    360         }
    361     };
    362 
    363     private final DataRoamingSettingObserver mDataRoamingSettingObserver;
    364 
    365     private class DataRoamingSettingObserver extends ContentObserver {
    366         public DataRoamingSettingObserver(Handler handler) {
    367             super(handler);
    368         }
    369 
    370         public void register(Context context) {
    371             final ContentResolver resolver = context.getContentResolver();
    372             resolver.registerContentObserver(
    373                     Settings.Secure.getUriFor(Settings.Secure.DATA_ROAMING), false, this);
    374         }
    375 
    376         public void unregister(Context context) {
    377             final ContentResolver resolver = context.getContentResolver();
    378             resolver.unregisterContentObserver(this);
    379         }
    380 
    381         @Override
    382         public void onChange(boolean selfChange) {
    383             // already running on mPhone handler thread
    384             handleDataOnRoamingChange();
    385         }
    386     }
    387 
    388     /**
    389      * Maintian the sum of transmit and receive packets.
    390      *
    391      * The packet counts are initizlied and reset to -1 and
    392      * remain -1 until they can be updated.
    393      */
    394     public class TxRxSum {
    395         public long txPkts;
    396         public long rxPkts;
    397 
    398         public TxRxSum() {
    399             reset();
    400         }
    401 
    402         public TxRxSum(long txPkts, long rxPkts) {
    403             this.txPkts = txPkts;
    404             this.rxPkts = rxPkts;
    405         }
    406 
    407         public TxRxSum(TxRxSum sum) {
    408             txPkts = sum.txPkts;
    409             rxPkts = sum.rxPkts;
    410         }
    411 
    412         public void reset() {
    413             txPkts = -1;
    414             rxPkts = -1;
    415         }
    416 
    417         public String toString() {
    418             return "{txSum=" + txPkts + " rxSum=" + rxPkts + "}";
    419         }
    420 
    421         public void updateTxRxSum() {
    422             boolean txUpdated = false, rxUpdated = false;
    423             long txSum = 0, rxSum = 0;
    424             for (ApnContext apnContext : mApnContexts.values()) {
    425                 if (apnContext.getState() == State.CONNECTED) {
    426                     DataConnectionAc dcac = apnContext.getDataConnectionAc();
    427                     if (dcac == null) continue;
    428 
    429                     LinkProperties linkProp = dcac.getLinkPropertiesSync();
    430                     if (linkProp == null) continue;
    431 
    432                     String iface = linkProp.getInterfaceName();
    433 
    434                     if (iface != null) {
    435                         long stats = TrafficStats.getTxPackets(iface);
    436                         if (stats > 0) {
    437                             txUpdated = true;
    438                             txSum += stats;
    439                         }
    440                         stats = TrafficStats.getRxPackets(iface);
    441                         if (stats > 0) {
    442                             rxUpdated = true;
    443                             rxSum += stats;
    444                         }
    445                     }
    446                 }
    447             }
    448             if (txUpdated) this.txPkts = txSum;
    449             if (rxUpdated) this.rxPkts = rxSum;
    450         }
    451     }
    452 
    453     protected boolean isDataSetupCompleteOk(AsyncResult ar) {
    454         if (ar.exception != null) {
    455             if (DBG) log("isDataSetupCompleteOk return false, ar.result=" + ar.result);
    456             return false;
    457         }
    458         if (mFailDataSetupCounter <= 0) {
    459             if (DBG) log("isDataSetupCompleteOk return true");
    460             return true;
    461         }
    462         ar.result = mFailDataSetupFailCause;
    463         if (DBG) {
    464             log("isDataSetupCompleteOk return false" +
    465                     " mFailDataSetupCounter=" + mFailDataSetupCounter +
    466                     " mFailDataSetupFailCause=" + mFailDataSetupFailCause);
    467         }
    468         mFailDataSetupCounter -= 1;
    469         return false;
    470     }
    471 
    472     protected void onActionIntentReconnectAlarm(Intent intent) {
    473         String reason = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON);
    474         if (mState == State.FAILED) {
    475             Message msg = obtainMessage(EVENT_CLEAN_UP_CONNECTION);
    476             msg.arg1 = 0; // tearDown is false
    477             msg.arg2 = 0;
    478             msg.obj = reason;
    479             sendMessage(msg);
    480         }
    481         sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA));
    482     }
    483 
    484     protected void onActionIntentDataStallAlarm(Intent intent) {
    485         if (VDBG) log("onActionIntentDataStallAlarm: action=" + intent.getAction());
    486         Message msg = obtainMessage(EVENT_DATA_STALL_ALARM, intent.getAction());
    487         msg.arg1 = intent.getIntExtra(DATA_STALL_ALARM_TAG_EXTRA, 0);
    488         sendMessage(msg);
    489     }
    490 
    491     /**
    492      * Default constructor
    493      */
    494     protected DataConnectionTracker(PhoneBase phone) {
    495         super();
    496         mPhone = phone;
    497 
    498         IntentFilter filter = new IntentFilter();
    499         filter.addAction(getActionIntentReconnectAlarm());
    500         filter.addAction(Intent.ACTION_SCREEN_ON);
    501         filter.addAction(Intent.ACTION_SCREEN_OFF);
    502         filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
    503         filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
    504         filter.addAction(INTENT_SET_FAIL_DATA_SETUP_COUNTER);
    505 
    506         mUserDataEnabled = Settings.Secure.getInt(
    507                 mPhone.getContext().getContentResolver(), Settings.Secure.MOBILE_DATA, 1) == 1;
    508 
    509         // TODO: Why is this registering the phone as the receiver of the intent
    510         //       and not its own handler?
    511         mPhone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone);
    512 
    513         // This preference tells us 1) initial condition for "dataEnabled",
    514         // and 2) whether the RIL will setup the baseband to auto-PS attach.
    515 
    516         dataEnabled[APN_DEFAULT_ID] = SystemProperties.getBoolean(DEFALUT_DATA_ON_BOOT_PROP,
    517                                                                   true);
    518         if (dataEnabled[APN_DEFAULT_ID]) {
    519             enabledCount++;
    520         }
    521 
    522         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mPhone.getContext());
    523         mAutoAttachOnCreation = sp.getBoolean(PhoneBase.DATA_DISABLED_ON_BOOT_KEY, false);
    524 
    525         // watch for changes to Settings.Secure.DATA_ROAMING
    526         mDataRoamingSettingObserver = new DataRoamingSettingObserver(mPhone);
    527         mDataRoamingSettingObserver.register(mPhone.getContext());
    528     }
    529 
    530     public void dispose() {
    531         for (DataConnectionAc dcac : mDataConnectionAsyncChannels.values()) {
    532             dcac.disconnect();
    533         }
    534         mDataConnectionAsyncChannels.clear();
    535         mIsDisposed = true;
    536         mPhone.getContext().unregisterReceiver(this.mIntentReceiver);
    537         mDataRoamingSettingObserver.unregister(mPhone.getContext());
    538     }
    539 
    540     protected void broadcastMessenger() {
    541         Intent intent = new Intent(ACTION_DATA_CONNECTION_TRACKER_MESSENGER);
    542         intent.putExtra(EXTRA_MESSENGER, new Messenger(this));
    543         mPhone.getContext().sendBroadcast(intent);
    544     }
    545 
    546     public Activity getActivity() {
    547         return mActivity;
    548     }
    549 
    550     public boolean isApnTypeActive(String type) {
    551         // TODO: support simultaneous with List instead
    552         if (Phone.APN_TYPE_DUN.equals(type)) {
    553             ApnSetting dunApn = fetchDunApn();
    554             if (dunApn != null) {
    555                 return ((mActiveApn != null) && (dunApn.toString().equals(mActiveApn.toString())));
    556             }
    557         }
    558         return mActiveApn != null && mActiveApn.canHandleType(type);
    559     }
    560 
    561     protected ApnSetting fetchDunApn() {
    562         Context c = mPhone.getContext();
    563         String apnData = Settings.Secure.getString(c.getContentResolver(),
    564                 Settings.Secure.TETHER_DUN_APN);
    565         ApnSetting dunSetting = ApnSetting.fromString(apnData);
    566         if (dunSetting != null) return dunSetting;
    567 
    568         apnData = c.getResources().getString(R.string.config_tether_apndata);
    569         return ApnSetting.fromString(apnData);
    570     }
    571 
    572     public String[] getActiveApnTypes() {
    573         String[] result;
    574         if (mActiveApn != null) {
    575             result = mActiveApn.types;
    576         } else {
    577             result = new String[1];
    578             result[0] = Phone.APN_TYPE_DEFAULT;
    579         }
    580         return result;
    581     }
    582 
    583     /** TODO: See if we can remove */
    584     public String getActiveApnString(String apnType) {
    585         String result = null;
    586         if (mActiveApn != null) {
    587             result = mActiveApn.apn;
    588         }
    589         return result;
    590     }
    591 
    592     /**
    593      * Modify {@link Settings.Secure#DATA_ROAMING} value.
    594      */
    595     public void setDataOnRoamingEnabled(boolean enabled) {
    596         if (getDataOnRoamingEnabled() != enabled) {
    597             final ContentResolver resolver = mPhone.getContext().getContentResolver();
    598             Settings.Secure.putInt(resolver, Settings.Secure.DATA_ROAMING, enabled ? 1 : 0);
    599             // will trigger handleDataOnRoamingChange() through observer
    600         }
    601     }
    602 
    603     /**
    604      * Return current {@link Settings.Secure#DATA_ROAMING} value.
    605      */
    606     public boolean getDataOnRoamingEnabled() {
    607         try {
    608             final ContentResolver resolver = mPhone.getContext().getContentResolver();
    609             return Settings.Secure.getInt(resolver, Settings.Secure.DATA_ROAMING) != 0;
    610         } catch (SettingNotFoundException snfe) {
    611             return false;
    612         }
    613     }
    614 
    615     private void handleDataOnRoamingChange() {
    616         if (mPhone.getServiceState().getRoaming()) {
    617             if (getDataOnRoamingEnabled()) {
    618                 resetAllRetryCounts();
    619             }
    620             sendMessage(obtainMessage(EVENT_ROAMING_ON));
    621         }
    622     }
    623 
    624     // abstract methods
    625     protected abstract String getActionIntentReconnectAlarm();
    626     protected abstract String getActionIntentDataStallAlarm();
    627     protected abstract void startNetStatPoll();
    628     protected abstract void stopNetStatPoll();
    629     protected abstract void restartDataStallAlarm();
    630     protected abstract void restartRadio();
    631     protected abstract void log(String s);
    632     protected abstract void loge(String s);
    633     protected abstract boolean isDataAllowed();
    634     protected abstract boolean isApnTypeAvailable(String type);
    635     public    abstract State getState(String apnType);
    636     protected abstract void setState(State s);
    637     protected abstract void gotoIdleAndNotifyDataConnection(String reason);
    638 
    639     protected abstract boolean onTrySetupData(String reason);
    640     protected abstract void onRoamingOff();
    641     protected abstract void onRoamingOn();
    642     protected abstract void onRadioAvailable();
    643     protected abstract void onRadioOffOrNotAvailable();
    644     protected abstract void onDataSetupComplete(AsyncResult ar);
    645     protected abstract void onDisconnectDone(int connId, AsyncResult ar);
    646     protected abstract void onVoiceCallStarted();
    647     protected abstract void onVoiceCallEnded();
    648     protected abstract void onCleanUpConnection(boolean tearDown, int apnId, String reason);
    649     protected abstract void onCleanUpAllConnections(String cause);
    650     protected abstract boolean isDataPossible(String apnType);
    651 
    652     protected void onDataStallAlarm(int tag) {
    653         loge("onDataStallAlarm: not impleted tag=" + tag);
    654     }
    655 
    656     @Override
    657     public void handleMessage(Message msg) {
    658         switch (msg.what) {
    659             case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
    660                 log("DISCONNECTED_CONNECTED: msg=" + msg);
    661                 DataConnectionAc dcac = (DataConnectionAc) msg.obj;
    662                 mDataConnectionAsyncChannels.remove(dcac.dataConnection.getDataConnectionId());
    663                 dcac.disconnected();
    664                 break;
    665             }
    666             case EVENT_ENABLE_NEW_APN:
    667                 onEnableApn(msg.arg1, msg.arg2);
    668                 break;
    669 
    670             case EVENT_TRY_SETUP_DATA:
    671                 String reason = null;
    672                 if (msg.obj instanceof String) {
    673                     reason = (String) msg.obj;
    674                 }
    675                 onTrySetupData(reason);
    676                 break;
    677 
    678             case EVENT_DATA_STALL_ALARM:
    679                 onDataStallAlarm(msg.arg1);
    680                 break;
    681 
    682             case EVENT_ROAMING_OFF:
    683                 if (getDataOnRoamingEnabled() == false) {
    684                     resetAllRetryCounts();
    685                 }
    686                 onRoamingOff();
    687                 break;
    688 
    689             case EVENT_ROAMING_ON:
    690                 onRoamingOn();
    691                 break;
    692 
    693             case EVENT_RADIO_AVAILABLE:
    694                 onRadioAvailable();
    695                 break;
    696 
    697             case EVENT_RADIO_OFF_OR_NOT_AVAILABLE:
    698                 onRadioOffOrNotAvailable();
    699                 break;
    700 
    701             case EVENT_DATA_SETUP_COMPLETE:
    702                 mCidActive = msg.arg1;
    703                 onDataSetupComplete((AsyncResult) msg.obj);
    704                 break;
    705 
    706             case EVENT_DISCONNECT_DONE:
    707                 log("DataConnectoinTracker.handleMessage: EVENT_DISCONNECT_DONE msg=" + msg);
    708                 onDisconnectDone(msg.arg1, (AsyncResult) msg.obj);
    709                 break;
    710 
    711             case EVENT_VOICE_CALL_STARTED:
    712                 onVoiceCallStarted();
    713                 break;
    714 
    715             case EVENT_VOICE_CALL_ENDED:
    716                 onVoiceCallEnded();
    717                 break;
    718 
    719             case EVENT_CLEAN_UP_ALL_CONNECTIONS: {
    720                 onCleanUpAllConnections((String) msg.obj);
    721                 break;
    722             }
    723             case EVENT_CLEAN_UP_CONNECTION: {
    724                 boolean tearDown = (msg.arg1 == 0) ? false : true;
    725                 onCleanUpConnection(tearDown, msg.arg2, (String) msg.obj);
    726                 break;
    727             }
    728             case EVENT_SET_INTERNAL_DATA_ENABLE: {
    729                 boolean enabled = (msg.arg1 == ENABLED) ? true : false;
    730                 onSetInternalDataEnabled(enabled);
    731                 break;
    732             }
    733             case EVENT_RESET_DONE: {
    734                 if (DBG) log("EVENT_RESET_DONE");
    735                 onResetDone((AsyncResult) msg.obj);
    736                 break;
    737             }
    738             case CMD_SET_USER_DATA_ENABLE: {
    739                 final boolean enabled = (msg.arg1 == ENABLED) ? true : false;
    740                 if (DBG) log("CMD_SET_USER_DATA_ENABLE enabled=" + enabled);
    741                 onSetUserDataEnabled(enabled);
    742                 break;
    743             }
    744             case CMD_SET_DEPENDENCY_MET: {
    745                 boolean met = (msg.arg1 == ENABLED) ? true : false;
    746                 if (DBG) log("CMD_SET_DEPENDENCY_MET met=" + met);
    747                 Bundle bundle = msg.getData();
    748                 if (bundle != null) {
    749                     String apnType = (String)bundle.get(APN_TYPE_KEY);
    750                     if (apnType != null) {
    751                         onSetDependencyMet(apnType, met);
    752                     }
    753                 }
    754                 break;
    755             }
    756             case CMD_SET_POLICY_DATA_ENABLE: {
    757                 final boolean enabled = (msg.arg1 == ENABLED) ? true : false;
    758                 onSetPolicyDataEnabled(enabled);
    759                 break;
    760             }
    761             default:
    762                 Log.e("DATA", "Unidentified event msg=" + msg);
    763                 break;
    764         }
    765     }
    766 
    767     /**
    768      * Report on whether data connectivity is enabled
    769      *
    770      * @return {@code false} if data connectivity has been explicitly disabled,
    771      *         {@code true} otherwise.
    772      */
    773     public boolean getAnyDataEnabled() {
    774         final boolean result;
    775         synchronized (mDataEnabledLock) {
    776             result = (mInternalDataEnabled && mUserDataEnabled && sPolicyDataEnabled
    777                     && (enabledCount != 0));
    778         }
    779         if (!result && DBG) log("getAnyDataEnabled " + result);
    780         return result;
    781     }
    782 
    783     protected boolean isEmergency() {
    784         final boolean result;
    785         synchronized (mDataEnabledLock) {
    786             result = mPhone.isInEcm() || mPhone.isInEmergencyCall();
    787         }
    788         log("isEmergency: result=" + result);
    789         return result;
    790     }
    791 
    792     protected int apnTypeToId(String type) {
    793         if (TextUtils.equals(type, Phone.APN_TYPE_DEFAULT)) {
    794             return APN_DEFAULT_ID;
    795         } else if (TextUtils.equals(type, Phone.APN_TYPE_MMS)) {
    796             return APN_MMS_ID;
    797         } else if (TextUtils.equals(type, Phone.APN_TYPE_SUPL)) {
    798             return APN_SUPL_ID;
    799         } else if (TextUtils.equals(type, Phone.APN_TYPE_DUN)) {
    800             return APN_DUN_ID;
    801         } else if (TextUtils.equals(type, Phone.APN_TYPE_HIPRI)) {
    802             return APN_HIPRI_ID;
    803         } else if (TextUtils.equals(type, Phone.APN_TYPE_IMS)) {
    804             return APN_IMS_ID;
    805         } else if (TextUtils.equals(type, Phone.APN_TYPE_FOTA)) {
    806             return APN_FOTA_ID;
    807         } else if (TextUtils.equals(type, Phone.APN_TYPE_CBS)) {
    808             return APN_CBS_ID;
    809         } else {
    810             return APN_INVALID_ID;
    811         }
    812     }
    813 
    814     protected String apnIdToType(int id) {
    815         switch (id) {
    816         case APN_DEFAULT_ID:
    817             return Phone.APN_TYPE_DEFAULT;
    818         case APN_MMS_ID:
    819             return Phone.APN_TYPE_MMS;
    820         case APN_SUPL_ID:
    821             return Phone.APN_TYPE_SUPL;
    822         case APN_DUN_ID:
    823             return Phone.APN_TYPE_DUN;
    824         case APN_HIPRI_ID:
    825             return Phone.APN_TYPE_HIPRI;
    826         case APN_IMS_ID:
    827             return Phone.APN_TYPE_IMS;
    828         case APN_FOTA_ID:
    829             return Phone.APN_TYPE_FOTA;
    830         case APN_CBS_ID:
    831             return Phone.APN_TYPE_CBS;
    832         default:
    833             log("Unknown id (" + id + ") in apnIdToType");
    834             return Phone.APN_TYPE_DEFAULT;
    835         }
    836     }
    837 
    838     protected LinkProperties getLinkProperties(String apnType) {
    839         int id = apnTypeToId(apnType);
    840 
    841         if (isApnIdEnabled(id)) {
    842             // TODO - remove this cdma-only hack and support multiple DCs.
    843             DataConnectionAc dcac = mDataConnectionAsyncChannels.get(0);
    844             return dcac.getLinkPropertiesSync();
    845         } else {
    846             return new LinkProperties();
    847         }
    848     }
    849 
    850     protected LinkCapabilities getLinkCapabilities(String apnType) {
    851         int id = apnTypeToId(apnType);
    852         if (isApnIdEnabled(id)) {
    853             // TODO - remove this cdma-only hack and support multiple DCs.
    854             DataConnectionAc dcac = mDataConnectionAsyncChannels.get(0);
    855             return dcac.getLinkCapabilitiesSync();
    856         } else {
    857             return new LinkCapabilities();
    858         }
    859     }
    860 
    861     // tell all active apns of the current condition
    862     protected void notifyDataConnection(String reason) {
    863         for (int id = 0; id < APN_NUM_TYPES; id++) {
    864             if (dataEnabled[id]) {
    865                 mPhone.notifyDataConnection(reason, apnIdToType(id));
    866             }
    867         }
    868         notifyOffApnsOfAvailability(reason);
    869     }
    870 
    871     // a new APN has gone active and needs to send events to catch up with the
    872     // current condition
    873     private void notifyApnIdUpToCurrent(String reason, int apnId) {
    874         switch (mState) {
    875             case IDLE:
    876             case INITING:
    877                 break;
    878             case CONNECTING:
    879             case SCANNING:
    880                 mPhone.notifyDataConnection(reason, apnIdToType(apnId), Phone.DataState.CONNECTING);
    881                 break;
    882             case CONNECTED:
    883             case DISCONNECTING:
    884                 mPhone.notifyDataConnection(reason, apnIdToType(apnId), Phone.DataState.CONNECTING);
    885                 mPhone.notifyDataConnection(reason, apnIdToType(apnId), Phone.DataState.CONNECTED);
    886                 break;
    887         }
    888     }
    889 
    890     // since we normally don't send info to a disconnected APN, we need to do this specially
    891     private void notifyApnIdDisconnected(String reason, int apnId) {
    892         mPhone.notifyDataConnection(reason, apnIdToType(apnId), Phone.DataState.DISCONNECTED);
    893     }
    894 
    895     // disabled apn's still need avail/unavail notificiations - send them out
    896     protected void notifyOffApnsOfAvailability(String reason) {
    897         if (DBG) log("notifyOffApnsOfAvailability - reason= " + reason);
    898         for (int id = 0; id < APN_NUM_TYPES; id++) {
    899             if (!isApnIdEnabled(id)) {
    900                 notifyApnIdDisconnected(reason, id);
    901             }
    902         }
    903     }
    904 
    905     public boolean isApnTypeEnabled(String apnType) {
    906         if (apnType == null) {
    907             return false;
    908         } else {
    909             return isApnIdEnabled(apnTypeToId(apnType));
    910         }
    911     }
    912 
    913     protected synchronized boolean isApnIdEnabled(int id) {
    914         if (id != APN_INVALID_ID) {
    915             return dataEnabled[id];
    916         }
    917         return false;
    918     }
    919 
    920     /**
    921      * Ensure that we are connected to an APN of the specified type.
    922      *
    923      * @param type the APN type (currently the only valid values are
    924      *            {@link Phone#APN_TYPE_MMS} and {@link Phone#APN_TYPE_SUPL})
    925      * @return Success is indicated by {@code Phone.APN_ALREADY_ACTIVE} or
    926      *         {@code Phone.APN_REQUEST_STARTED}. In the latter case, a
    927      *         broadcast will be sent by the ConnectivityManager when a
    928      *         connection to the APN has been established.
    929      */
    930     public synchronized int enableApnType(String type) {
    931         int id = apnTypeToId(type);
    932         if (id == APN_INVALID_ID) {
    933             return Phone.APN_REQUEST_FAILED;
    934         }
    935 
    936         if (DBG) {
    937             log("enableApnType(" + type + "), isApnTypeActive = " + isApnTypeActive(type)
    938                     + ", isApnIdEnabled =" + isApnIdEnabled(id) + " and state = " + mState);
    939         }
    940 
    941         if (!isApnTypeAvailable(type)) {
    942             if (DBG) log("type not available");
    943             return Phone.APN_TYPE_NOT_AVAILABLE;
    944         }
    945 
    946         if (isApnIdEnabled(id)) {
    947             return Phone.APN_ALREADY_ACTIVE;
    948         } else {
    949             setEnabled(id, true);
    950         }
    951         return Phone.APN_REQUEST_STARTED;
    952     }
    953 
    954     /**
    955      * The APN of the specified type is no longer needed. Ensure that if use of
    956      * the default APN has not been explicitly disabled, we are connected to the
    957      * default APN.
    958      *
    959      * @param type the APN type. The only valid values are currently
    960      *            {@link Phone#APN_TYPE_MMS} and {@link Phone#APN_TYPE_SUPL}.
    961      * @return Success is indicated by {@code Phone.APN_ALREADY_ACTIVE} or
    962      *         {@code Phone.APN_REQUEST_STARTED}. In the latter case, a
    963      *         broadcast will be sent by the ConnectivityManager when a
    964      *         connection to the APN has been disconnected. A {@code
    965      *         Phone.APN_REQUEST_FAILED} is returned if the type parameter is
    966      *         invalid or if the apn wasn't enabled.
    967      */
    968     public synchronized int disableApnType(String type) {
    969         if (DBG) log("disableApnType(" + type + ")");
    970         int id = apnTypeToId(type);
    971         if (id == APN_INVALID_ID) {
    972             return Phone.APN_REQUEST_FAILED;
    973         }
    974         if (isApnIdEnabled(id)) {
    975             setEnabled(id, false);
    976             if (isApnTypeActive(Phone.APN_TYPE_DEFAULT)) {
    977                 if (dataEnabled[APN_DEFAULT_ID]) {
    978                     return Phone.APN_ALREADY_ACTIVE;
    979                 } else {
    980                     return Phone.APN_REQUEST_STARTED;
    981                 }
    982             } else {
    983                 return Phone.APN_REQUEST_STARTED;
    984             }
    985         } else {
    986             return Phone.APN_REQUEST_FAILED;
    987         }
    988     }
    989 
    990     protected void setEnabled(int id, boolean enable) {
    991         if (DBG) {
    992             log("setEnabled(" + id + ", " + enable + ") with old state = " + dataEnabled[id]
    993                     + " and enabledCount = " + enabledCount);
    994         }
    995         Message msg = obtainMessage(EVENT_ENABLE_NEW_APN);
    996         msg.arg1 = id;
    997         msg.arg2 = (enable ? ENABLED : DISABLED);
    998         sendMessage(msg);
    999     }
   1000 
   1001     protected void onEnableApn(int apnId, int enabled) {
   1002         if (DBG) {
   1003             log("EVENT_APN_ENABLE_REQUEST apnId=" + apnId + ", apnType=" + apnIdToType(apnId) +
   1004                     ", enabled=" + enabled + ", dataEnabled = " + dataEnabled[apnId] +
   1005                     ", enabledCount = " + enabledCount + ", isApnTypeActive = " +
   1006                     isApnTypeActive(apnIdToType(apnId)));
   1007         }
   1008         if (enabled == ENABLED) {
   1009             synchronized (this) {
   1010                 if (!dataEnabled[apnId]) {
   1011                     dataEnabled[apnId] = true;
   1012                     enabledCount++;
   1013                 }
   1014             }
   1015             String type = apnIdToType(apnId);
   1016             if (!isApnTypeActive(type)) {
   1017                 mRequestedApnType = type;
   1018                 onEnableNewApn();
   1019             } else {
   1020                 notifyApnIdUpToCurrent(Phone.REASON_APN_SWITCHED, apnId);
   1021             }
   1022         } else {
   1023             // disable
   1024             boolean didDisable = false;
   1025             synchronized (this) {
   1026                 if (dataEnabled[apnId]) {
   1027                     dataEnabled[apnId] = false;
   1028                     enabledCount--;
   1029                     didDisable = true;
   1030                 }
   1031             }
   1032             if (didDisable) {
   1033                 if ((enabledCount == 0) || (apnId == APN_DUN_ID)) {
   1034                     mRequestedApnType = Phone.APN_TYPE_DEFAULT;
   1035                     onCleanUpConnection(true, apnId, Phone.REASON_DATA_DISABLED);
   1036                 }
   1037 
   1038                 // send the disconnect msg manually, since the normal route wont send
   1039                 // it (it's not enabled)
   1040                 notifyApnIdDisconnected(Phone.REASON_DATA_DISABLED, apnId);
   1041                 if (dataEnabled[APN_DEFAULT_ID] == true
   1042                         && !isApnTypeActive(Phone.APN_TYPE_DEFAULT)) {
   1043                     // TODO - this is an ugly way to restore the default conn - should be done
   1044                     // by a real contention manager and policy that disconnects the lower pri
   1045                     // stuff as enable requests come in and pops them back on as we disable back
   1046                     // down to the lower pri stuff
   1047                     mRequestedApnType = Phone.APN_TYPE_DEFAULT;
   1048                     onEnableNewApn();
   1049                 }
   1050             }
   1051         }
   1052     }
   1053 
   1054     /**
   1055      * Called when we switch APNs.
   1056      *
   1057      * mRequestedApnType is set prior to call
   1058      * To be overridden.
   1059      */
   1060     protected void onEnableNewApn() {
   1061     }
   1062 
   1063     /**
   1064      * Called when EVENT_RESET_DONE is received so goto
   1065      * IDLE state and send notifications to those interested.
   1066      *
   1067      * TODO - currently unused.  Needs to be hooked into DataConnection cleanup
   1068      * TODO - needs to pass some notion of which connection is reset..
   1069      */
   1070     protected void onResetDone(AsyncResult ar) {
   1071         if (DBG) log("EVENT_RESET_DONE");
   1072         String reason = null;
   1073         if (ar.userObj instanceof String) {
   1074             reason = (String) ar.userObj;
   1075         }
   1076         gotoIdleAndNotifyDataConnection(reason);
   1077     }
   1078 
   1079     /**
   1080      * Prevent mobile data connections from being established, or once again
   1081      * allow mobile data connections. If the state toggles, then either tear
   1082      * down or set up data, as appropriate to match the new state.
   1083      *
   1084      * @param enable indicates whether to enable ({@code true}) or disable (
   1085      *            {@code false}) data
   1086      * @return {@code true} if the operation succeeded
   1087      */
   1088     public boolean setInternalDataEnabled(boolean enable) {
   1089         if (DBG)
   1090             log("setInternalDataEnabled(" + enable + ")");
   1091 
   1092         Message msg = obtainMessage(EVENT_SET_INTERNAL_DATA_ENABLE);
   1093         msg.arg1 = (enable ? ENABLED : DISABLED);
   1094         sendMessage(msg);
   1095         return true;
   1096     }
   1097 
   1098     protected void onSetInternalDataEnabled(boolean enabled) {
   1099         synchronized (mDataEnabledLock) {
   1100             mInternalDataEnabled = enabled;
   1101             if (enabled) {
   1102                 log("onSetInternalDataEnabled: changed to enabled, try to setup data call");
   1103                 resetAllRetryCounts();
   1104                 onTrySetupData(Phone.REASON_DATA_ENABLED);
   1105             } else {
   1106                 log("onSetInternalDataEnabled: changed to disabled, cleanUpAllConnections");
   1107                 cleanUpAllConnections(null);
   1108             }
   1109         }
   1110     }
   1111 
   1112     public void cleanUpAllConnections(String cause) {
   1113         Message msg = obtainMessage(EVENT_CLEAN_UP_ALL_CONNECTIONS);
   1114         msg.obj = cause;
   1115         sendMessage(msg);
   1116     }
   1117 
   1118     public abstract boolean isDisconnected();
   1119 
   1120     protected void onSetUserDataEnabled(boolean enabled) {
   1121         synchronized (mDataEnabledLock) {
   1122             final boolean prevEnabled = getAnyDataEnabled();
   1123             if (mUserDataEnabled != enabled) {
   1124                 mUserDataEnabled = enabled;
   1125                 Settings.Secure.putInt(mPhone.getContext().getContentResolver(),
   1126                         Settings.Secure.MOBILE_DATA, enabled ? 1 : 0);
   1127                 if (prevEnabled != getAnyDataEnabled()) {
   1128                     if (!prevEnabled) {
   1129                         resetAllRetryCounts();
   1130                         onTrySetupData(Phone.REASON_DATA_ENABLED);
   1131                     } else {
   1132                         onCleanUpAllConnections(Phone.REASON_DATA_DISABLED);
   1133                     }
   1134                 }
   1135             }
   1136         }
   1137     }
   1138 
   1139     protected void onSetDependencyMet(String apnType, boolean met) {
   1140     }
   1141 
   1142     protected void onSetPolicyDataEnabled(boolean enabled) {
   1143         synchronized (mDataEnabledLock) {
   1144             final boolean prevEnabled = getAnyDataEnabled();
   1145             if (sPolicyDataEnabled != enabled) {
   1146                 sPolicyDataEnabled = enabled;
   1147                 if (prevEnabled != getAnyDataEnabled()) {
   1148                     if (!prevEnabled) {
   1149                         resetAllRetryCounts();
   1150                         onTrySetupData(Phone.REASON_DATA_ENABLED);
   1151                     } else {
   1152                         onCleanUpAllConnections(Phone.REASON_DATA_DISABLED);
   1153                     }
   1154                 }
   1155             }
   1156         }
   1157     }
   1158 
   1159     protected String getReryConfig(boolean forDefault) {
   1160         int rt = mPhone.getServiceState().getRadioTechnology();
   1161 
   1162         if ((rt == ServiceState.RADIO_TECHNOLOGY_IS95A) ||
   1163             (rt == ServiceState.RADIO_TECHNOLOGY_IS95B) ||
   1164             (rt == ServiceState.RADIO_TECHNOLOGY_1xRTT) ||
   1165             (rt == ServiceState.RADIO_TECHNOLOGY_EVDO_0) ||
   1166             (rt == ServiceState.RADIO_TECHNOLOGY_EVDO_A) ||
   1167             (rt == ServiceState.RADIO_TECHNOLOGY_EVDO_B) ||
   1168             (rt == ServiceState.RADIO_TECHNOLOGY_EHRPD)) {
   1169             // CDMA variant
   1170             return SystemProperties.get("ro.cdma.data_retry_config");
   1171         } else {
   1172             // Use GSM varient for all others.
   1173             if (forDefault) {
   1174                 return SystemProperties.get("ro.gsm.data_retry_config");
   1175             } else {
   1176                 return SystemProperties.get("ro.gsm.2nd_data_retry_config");
   1177             }
   1178         }
   1179     }
   1180 
   1181     protected void resetAllRetryCounts() {
   1182         for (DataConnection dc : mDataConnections.values()) {
   1183             dc.resetRetryCount();
   1184         }
   1185     }
   1186 }
   1187