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