OSDN Git Service

Add external dependency API.
authorRobert Greenwalt <rgreenwalt@google.com>
Fri, 25 Mar 2011 20:09:25 +0000 (13:09 -0700)
committerRobert Greenwalt <rgreenwalt@google.com>
Thu, 7 Apr 2011 19:28:37 +0000 (12:28 -0700)
An APN will not be connected to if some external dependency is not met.

bug:3486704
Change-Id: I7d94df343b260013efd11faa978deb13f07f1389

16 files changed:
core/java/android/bluetooth/BluetoothTetheringDataTracker.java
core/java/android/net/ConnectivityManager.java
core/java/android/net/DummyDataStateTracker.java
core/java/android/net/IConnectivityManager.aidl
core/java/android/net/MobileDataStateTracker.java
core/java/android/net/NetworkConfig.java [new file with mode: 0644]
core/java/android/net/NetworkStateTracker.java
core/res/res/values/config.xml
services/java/com/android/server/ConnectivityService.java
telephony/java/com/android/internal/telephony/ApnContext.java
telephony/java/com/android/internal/telephony/DataConnection.java
telephony/java/com/android/internal/telephony/DataConnectionTracker.java
telephony/java/com/android/internal/telephony/Phone.java
telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java
telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
wifi/java/android/net/wifi/WifiStateTracker.java

index c08f14f..a7b0037 100644 (file)
@@ -300,4 +300,8 @@ public class BluetoothTetheringDataTracker implements NetworkStateTracker {
         msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
         msg.sendToTarget();
     }
+
+    public void setDependencyMet(boolean met) {
+        // not supported on this network
+    }
 }
index 26f375d..b541ec3 100644 (file)
@@ -690,4 +690,16 @@ public class ConnectivityManager
             return null;
         }
     }
+
+    /**
+     * @param networkType The network who's dependence has changed
+     * @param met Boolean - true if network use is ok, false if not
+     * {@hide}
+     */
+    public void setDataDependency(int networkType, boolean met) {
+        try {
+            mService.setDataDependency(networkType, met);
+        } catch (RemoteException e) {
+        }
+    }
 }
index d0c77cf..e39725a 100644 (file)
@@ -191,6 +191,10 @@ public class DummyDataStateTracker implements NetworkStateTracker {
         return new LinkCapabilities(mLinkCapabilities);
     }
 
+    public void setDependencyMet(boolean met) {
+        // not supported on this network
+    }
+
     static private void log(String s) {
         Slog.d(TAG, s);
     }
index 70ab4f1..8be492c 100644 (file)
@@ -92,4 +92,6 @@ interface IConnectivityManager
     void setGlobalProxy(in ProxyProperties p);
 
     ProxyProperties getProxy();
+
+    void setDataDependency(int networkType, boolean met);
 }
index 5b4da66..bb6ee0f 100644 (file)
@@ -20,6 +20,7 @@ import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.os.Bundle;
 import android.os.HandlerThread;
 import android.os.Looper;
 import android.os.Messenger;
@@ -493,6 +494,25 @@ public class MobileDataStateTracker implements NetworkStateTracker {
         }
     }
 
+    /**
+     * carrier dependency is met/unmet
+     * @param met
+     */
+    public void setDependencyMet(boolean met) {
+        Bundle bundle = Bundle.forPair(DataConnectionTracker.APN_TYPE_KEY, mApnType);
+        try {
+            log("setDependencyMet: E met=" + met);
+            Message msg = Message.obtain();
+            msg.what = DataConnectionTracker.CMD_SET_DEPENDENCY_MET;
+            msg.arg1 = (met ? DataConnectionTracker.ENABLED : DataConnectionTracker.DISABLED);
+            msg.setData(bundle);
+            mDataConnectionTrackerAc.sendMessage(msg);
+            log("setDependencyMet: X met=" + met);
+        } catch (NullPointerException e) {
+            log("setDependencyMet: X mAc was null" + e);
+        }
+    }
+
     @Override
     public String toString() {
         StringBuffer sb = new StringBuffer("Mobile data state: ");
diff --git a/core/java/android/net/NetworkConfig.java b/core/java/android/net/NetworkConfig.java
new file mode 100644 (file)
index 0000000..4adb76b
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.util.Log;
+
+/**
+ * Describes the buildtime configuration of a network.
+ * Holds settings read from resources.
+ * @hide
+ */
+public class NetworkConfig {
+    /**
+     * Human readable string
+     */
+    public String name;
+
+    /**
+     * Type from ConnectivityManager
+     */
+    public int type;
+
+    /**
+     * the radio number from radio attributes config
+     */
+    public int radio;
+
+    /**
+     * higher number == higher priority when turning off connections
+     */
+    public int priority;
+
+    /**
+     * indicates the boot time dependencyMet setting
+     */
+    public boolean dependencyMet;
+
+    /**
+     * input string from config.xml resource.  Uses the form:
+     * [Connection name],[ConnectivityManager connection type],
+     * [associated radio-type],[priority],[dependencyMet]
+     */
+    public NetworkConfig(String init) {
+        String fragments[] = init.split(",");
+        name = fragments[0].trim().toLowerCase();
+        type = Integer.parseInt(fragments[1]);
+        radio = Integer.parseInt(fragments[2]);
+        priority = Integer.parseInt(fragments[3]);
+        if (fragments.length > 4) {
+            dependencyMet = Boolean.parseBoolean(fragments[4]);
+        } else {
+            dependencyMet = true;
+        }
+    }
+
+    /**
+     * Indicates if this network is supposed to be default-routable
+     */
+    public boolean isDefault() {
+        return (type == radio);
+    }
+}
index eb97d77..f53063d 100644 (file)
@@ -176,4 +176,9 @@ public interface NetworkStateTracker {
      * Indicate tear down requested from connectivity
      */
     public void setTeardownRequested(boolean isRequested);
+
+    /**
+     * An external dependency has been met/unmet
+     */
+    public void setDependencyMet(boolean met);
 }
index 2037191..6695296 100755 (executable)
          based on the hardware -->
     <!-- An Array of "[Connection name],[ConnectivityManager connection type],
          [associated radio-type],[priority]  -->
+    <!-- an optional 5th element can be added indicating boot-time dependency-met value.  Defaults to true -->
     <string-array translatable="false" name="networkAttributes">
         <item>"wifi,1,1,1"</item>
         <item>"mobile,0,0,0"</item>
index f170cb7..d3349cc 100644 (file)
@@ -27,6 +27,7 @@ import android.net.DummyDataStateTracker;
 import android.net.IConnectivityManager;
 import android.net.LinkProperties;
 import android.net.MobileDataStateTracker;
+import android.net.NetworkConfig;
 import android.net.NetworkInfo;
 import android.net.NetworkStateTracker;
 import android.net.NetworkUtils;
@@ -188,6 +189,14 @@ public class ConnectivityService extends IConnectivityManager.Stub {
     private static final int EVENT_APPLY_GLOBAL_HTTP_PROXY =
             MAX_NETWORK_STATE_TRACKER_EVENT + 9;
 
+    /**
+     * used internally to set external dependency met/unmet
+     * arg1 = ENABLED (met) or DISABLED (unmet)
+     * arg2 = NetworkType
+     */
+    private static final int EVENT_SET_DEPENDENCY_MET =
+            MAX_NETWORK_STATE_TRACKER_EVENT + 10;
+
     private Handler mHandler;
 
     // list of DeathRecipients used to make sure features are turned off when
@@ -216,28 +225,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
 
     private SettingsObserver mSettingsObserver;
 
-    private static class NetworkAttributes {
-        /**
-         * Class for holding settings read from resources.
-         */
-        public String mName;
-        public int mType;
-        public int mRadio;
-        public int mPriority;
-        public NetworkInfo.State mLastState;
-        public NetworkAttributes(String init) {
-            String fragments[] = init.split(",");
-            mName = fragments[0].toLowerCase();
-            mType = Integer.parseInt(fragments[1]);
-            mRadio = Integer.parseInt(fragments[2]);
-            mPriority = Integer.parseInt(fragments[3]);
-            mLastState = NetworkInfo.State.UNKNOWN;
-        }
-        public boolean isDefault() {
-            return (mType == mRadio);
-        }
-    }
-    NetworkAttributes[] mNetAttributes;
+    NetworkConfig[] mNetConfigs;
     int mNetworksDefined;
 
     private static class RadioAttributes {
@@ -304,7 +292,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
         mNetworkPreference = getPersistedNetworkPreference();
 
         mRadioAttributes = new RadioAttributes[ConnectivityManager.MAX_RADIO_TYPE+1];
-        mNetAttributes = new NetworkAttributes[ConnectivityManager.MAX_NETWORK_TYPE+1];
+        mNetConfigs = new NetworkConfig[ConnectivityManager.MAX_NETWORK_TYPE+1];
 
         // Load device network attributes from resources
         String[] raStrings = context.getResources().getStringArray(
@@ -327,13 +315,13 @@ public class ConnectivityService extends IConnectivityManager.Stub {
                 com.android.internal.R.array.networkAttributes);
         for (String naString : naStrings) {
             try {
-                NetworkAttributes n = new NetworkAttributes(naString);
+                NetworkConfig n = new NetworkConfig(naString);
                 if (n.mType > ConnectivityManager.MAX_NETWORK_TYPE) {
                     loge("Error in networkAttributes - ignoring attempt to define type " +
                             n.mType);
                     continue;
                 }
-                if (mNetAttributes[n.mType] != null) {
+                if (mNetConfigs[n.mType] != null) {
                     loge("Error in networkAttributes - ignoring attempt to redefine type " +
                             n.mType);
                     continue;
@@ -343,7 +331,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
                             "radio " + n.mRadio + " in network type " + n.mType);
                     continue;
                 }
-                mNetAttributes[n.mType] = n;
+                mNetConfigs[n.mType] = n;
                 mNetworksDefined++;
             } catch(Exception e) {
                 // ignore it - leave the entry null
@@ -357,7 +345,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
             int currentLowest = 0;
             int nextLowest = 0;
             while (insertionPoint > -1) {
-                for (NetworkAttributes na : mNetAttributes) {
+                for (NetworkConfig na : mNetConfigs) {
                     if (na == null) continue;
                     if (na.mPriority < currentLowest) continue;
                     if (na.mPriority > currentLowest) {
@@ -392,7 +380,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
          * to change very often.
          */
         for (int netType : mPriorityList) {
-            switch (mNetAttributes[netType].mRadio) {
+            switch (mNetConfigs[netType].mRadio) {
             case ConnectivityManager.TYPE_WIFI:
                 if (DBG) log("Starting Wifi Service.");
                 WifiStateTracker wst = new WifiStateTracker();
@@ -408,12 +396,12 @@ public class ConnectivityService extends IConnectivityManager.Stub {
                 break;
             case ConnectivityManager.TYPE_MOBILE:
                 mNetTrackers[netType] = new MobileDataStateTracker(netType,
-                        mNetAttributes[netType].mName);
+                        mNetConfigs[netType].mName);
                 mNetTrackers[netType].startMonitoring(context, mHandler);
                 break;
             case ConnectivityManager.TYPE_DUMMY:
                 mNetTrackers[netType] = new DummyDataStateTracker(netType,
-                        mNetAttributes[netType].mName);
+                        mNetConfigs[netType].mName);
                 mNetTrackers[netType].startMonitoring(context, mHandler);
                 break;
             case ConnectivityManager.TYPE_BLUETOOTH:
@@ -422,7 +410,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
                 break;
             default:
                 loge("Trying to create a DataStateTracker for an unknown radio type " +
-                        mNetAttributes[netType].mRadio);
+                        mNetConfigs[netType].mRadio);
                 continue;
             }
         }
@@ -469,8 +457,8 @@ public class ConnectivityService extends IConnectivityManager.Stub {
 
     private void handleSetNetworkPreference(int preference) {
         if (ConnectivityManager.isNetworkTypeValid(preference) &&
-                mNetAttributes[preference] != null &&
-                mNetAttributes[preference].isDefault()) {
+                mNetConfigs[preference] != null &&
+                mNetConfigs[preference].isDefault()) {
             if (mNetworkPreference != preference) {
                 final ContentResolver cr = mContext.getContentResolver();
                 Settings.Secure.putInt(cr, Settings.Secure.NETWORK_PREFERENCE, preference);
@@ -539,7 +527,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
     public NetworkInfo getActiveNetworkInfo() {
         enforceAccessPermission();
         for (int type=0; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) {
-            if (mNetAttributes[type] == null || !mNetAttributes[type].isDefault()) {
+            if (mNetConfigs[type] == null || !mNetConfigs[type].isDefault()) {
                 continue;
             }
             NetworkStateTracker t = mNetTrackers[type];
@@ -585,7 +573,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
     public LinkProperties getActiveLinkProperties() {
         enforceAccessPermission();
         for (int type=0; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) {
-            if (mNetAttributes[type] == null || !mNetAttributes[type].isDefault()) {
+            if (mNetConfigs[type] == null || !mNetConfigs[type].isDefault()) {
                 continue;
             }
             NetworkStateTracker t = mNetTrackers[type];
@@ -687,7 +675,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
         }
         enforceChangePermission();
         if (!ConnectivityManager.isNetworkTypeValid(networkType) ||
-                mNetAttributes[networkType] == null) {
+                mNetConfigs[networkType] == null) {
             return Phone.APN_REQUEST_FAILED;
         }
 
@@ -999,6 +987,24 @@ public class ConnectivityService extends IConnectivityManager.Stub {
         return retVal;
     }
 
+    public void setDataDependency(int networkType, boolean met) {
+        enforceChangePermission();
+        if (DBG) {
+            log("setDataDependency(" + networkType + ", " + met + ")");
+        }
+        mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_DEPENDENCY_MET,
+                (met ? ENABLED : DISABLED), networkType));
+    }
+
+    private void handleSetDependencyMet(int networkType, boolean met) {
+        if (mNetTrackers[networkType] != null) {
+            if (DBG) {
+                log("handleSetDependencyMet(" + networkType + ", " + met + ")");
+            }
+            mNetTrackers[networkType].setDependencyMet(met);
+        }
+    }
+
     /**
      * @see ConnectivityManager#setMobileDataEnabled(boolean)
      */
@@ -1007,7 +1013,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
         if (DBG) log("setMobileDataEnabled(" + enabled + ")");
 
         mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_MOBILE_DATA,
-            (enabled ? ENABLED : DISABLED), 0));
+                (enabled ? ENABLED : DISABLED), 0));
     }
 
     private void handleSetMobileData(boolean enabled) {
@@ -1068,7 +1074,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
          * getting the disconnect for a network that we explicitly disabled
          * in accordance with network preference policies.
          */
-        if (!mNetAttributes[prevNetType].isDefault()) {
+        if (!mNetConfigs[prevNetType].isDefault()) {
             List pids = mNetRequestersPids[prevNetType];
             for (int i = 0; i<pids.size(); i++) {
                 Integer pid = (Integer)pids.get(i);
@@ -1093,7 +1099,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
                     info.getExtraInfo());
         }
 
-        if (mNetAttributes[prevNetType].isDefault()) {
+        if (mNetConfigs[prevNetType].isDefault()) {
             tryFailover(prevNetType);
             if (mActiveDefaultNetwork != -1) {
                 NetworkInfo switchTo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo();
@@ -1123,7 +1129,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
          * Try to reconnect on all available and let them hash it out when
          * more than one connects.
          */
-        if (mNetAttributes[prevNetType].isDefault()) {
+        if (mNetConfigs[prevNetType].isDefault()) {
             if (mActiveDefaultNetwork == prevNetType) {
                 mActiveDefaultNetwork = -1;
             }
@@ -1133,12 +1139,12 @@ public class ConnectivityService extends IConnectivityManager.Stub {
             // TODO - don't filter by priority now - nice optimization but risky
 //            int currentPriority = -1;
 //            if (mActiveDefaultNetwork != -1) {
-//                currentPriority = mNetAttributes[mActiveDefaultNetwork].mPriority;
+//                currentPriority = mNetConfigs[mActiveDefaultNetwork].mPriority;
 //            }
             for (int checkType=0; checkType <= ConnectivityManager.MAX_NETWORK_TYPE; checkType++) {
                 if (checkType == prevNetType) continue;
-                if (mNetAttributes[checkType] == null) continue;
-                if (!mNetAttributes[checkType].isDefault()) continue;
+                if (mNetConfigs[checkType] == null) continue;
+                if (!mNetConfigs[checkType].isDefault()) continue;
 
 // Enabling the isAvailable() optimization caused mobile to not get
 // selected if it was in the middle of error handling. Specifically
@@ -1150,7 +1156,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
 // complete before it is really complete.
 //                if (!mNetTrackers[checkType].isAvailable()) continue;
 
-//                if (currentPriority >= mNetAttributes[checkType].mPriority) continue;
+//                if (currentPriority >= mNetConfigs[checkType].mPriority) continue;
 
                 NetworkStateTracker checkTracker = mNetTrackers[checkType];
                 NetworkInfo checkInfo = checkTracker.getNetworkInfo();
@@ -1223,7 +1229,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
             info.setFailover(false);
         }
 
-        if (mNetAttributes[info.getType()].isDefault()) {
+        if (mNetConfigs[info.getType()].isDefault()) {
             tryFailover(info.getType());
             if (mActiveDefaultNetwork != -1) {
                 NetworkInfo switchTo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo();
@@ -1276,11 +1282,11 @@ public class ConnectivityService extends IConnectivityManager.Stub {
 
         // if this is a default net and other default is running
         // kill the one not preferred
-        if (mNetAttributes[type].isDefault()) {
+        if (mNetConfigs[type].isDefault()) {
             if (mActiveDefaultNetwork != -1 && mActiveDefaultNetwork != type) {
                 if ((type != mNetworkPreference &&
-                        mNetAttributes[mActiveDefaultNetwork].mPriority >
-                        mNetAttributes[type].mPriority) ||
+                        mNetConfigs[mActiveDefaultNetwork].mPriority >
+                        mNetConfigs[type].mPriority) ||
                         mNetworkPreference == mActiveDefaultNetwork) {
                         // don't accept this one
                         if (DBG) {
@@ -1344,14 +1350,14 @@ public class ConnectivityService extends IConnectivityManager.Stub {
         handleDnsConfigurationChange(netType);
 
         if (mNetTrackers[netType].getNetworkInfo().isConnected()) {
-            if (mNetAttributes[netType].isDefault()) {
+            if (mNetConfigs[netType].isDefault()) {
                 handleApplyDefaultProxy(netType);
                 addDefaultRoute(mNetTrackers[netType]);
             } else {
                 addPrivateDnsRoutes(mNetTrackers[netType]);
             }
         } else {
-            if (mNetAttributes[netType].isDefault()) {
+            if (mNetConfigs[netType].isDefault()) {
                 removeDefaultRoute(mNetTrackers[netType]);
             } else {
                 removePrivateDnsRoutes(mNetTrackers[netType]);
@@ -1512,7 +1518,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
     {
         if (DBG) log("reassessPidDns for pid " + myPid);
         for(int i : mPriorityList) {
-            if (mNetAttributes[i].isDefault()) {
+            if (mNetConfigs[i].isDefault()) {
                 continue;
             }
             NetworkStateTracker nt = mNetTrackers[i];
@@ -1594,7 +1600,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
             if (p == null) return;
             Collection<InetAddress> dnses = p.getDnses();
             boolean changed = false;
-            if (mNetAttributes[netType].isDefault()) {
+            if (mNetConfigs[netType].isDefault()) {
                 int j = 1;
                 if (dnses.size() == 0 && mDefaultDns != null) {
                     String dnsString = mDefaultDns.getHostAddress();
@@ -1725,23 +1731,6 @@ public class ConnectivityService extends IConnectivityManager.Stub {
                     info = (NetworkInfo) msg.obj;
                     int type = info.getType();
                     NetworkInfo.State state = info.getState();
-                    // only do this optimization for wifi.  It going into scan mode for location
-                    // services generates alot of noise.  Meanwhile the mms apn won't send out
-                    // subsequent notifications when on default cellular because it never
-                    // disconnects..  so only do this to wifi notifications.  Fixed better when the
-                    // APN notifications are standardized.
-                    if (mNetAttributes[type].mLastState == state &&
-                            mNetAttributes[type].mRadio == ConnectivityManager.TYPE_WIFI) {
-                        if (DBG) {
-                            // TODO - remove this after we validate the dropping doesn't break
-                            // anything
-                            log("Dropping ConnectivityChange for " +
-                                    info.getTypeName() + ": " +
-                                    state + "/" + info.getDetailedState());
-                        }
-                        return;
-                    }
-                    mNetAttributes[type].mLastState = state;
 
                     if (DBG) log("ConnectivityChange for " +
                             info.getTypeName() + ": " +
@@ -1780,8 +1769,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
                     break;
                 case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED:
                     info = (NetworkInfo) msg.obj;
-                    type = info.getType();
-                    handleConnectivityChange(type);
+                    handleConnectivityChange(info.getType());
                     break;
                 case EVENT_CLEAR_NET_TRANSITION_WAKELOCK:
                     String causedBy = null;
@@ -1835,6 +1823,13 @@ public class ConnectivityService extends IConnectivityManager.Stub {
                 case EVENT_APPLY_GLOBAL_HTTP_PROXY:
                 {
                     handleDeprecatedGlobalHttpProxy();
+                    break;
+                }
+                case EVENT_SET_DEPENDENCY_MET:
+                {
+                    boolean met = (msg.arg1 == ENABLED);
+                    handleSetDependencyMet(msg.arg2, met);
+                    break;
                 }
             }
         }
index a86ea7e..2e7c3a3 100644 (file)
@@ -20,7 +20,6 @@ import android.app.PendingIntent;
 
 import android.util.Log;
 import java.util.ArrayList;
-import com.android.internal.telephony.gsm.GsmDataConnection;
 
 /**
  * Maintain the Apn context
@@ -30,9 +29,13 @@ public class ApnContext {
     public static final int PENDING_ACTION_NONE = 1;
     public static final int PENDING_ACTION_RECONNECT = 2;
     public static final int PENDING_ACTION_APN_DISABLE = 3;
+
+    public static final int DATA_ENABLED = 1;
+    public static final int DATA_DISABLED = 2;
+
     public final String LOG_TAG;
 
-    int pendingAction;
+    int mPendingAction;
 
     protected static final boolean DBG = true;
 
@@ -47,37 +50,49 @@ public class ApnContext {
 
     ApnSetting mApnSetting;
 
-    GsmDataConnection mDataConnection;
+    DataConnection mDataConnection;
 
     String mReason;
 
     PendingIntent mReconnectIntent;
 
+    /**
+     * user/app requested connection on this APN
+     */
+    boolean mDataEnabled;
+
+    /**
+     * carrier requirements met
+     */
+    boolean mDependencyMet;
+
     public ApnContext(String apnType, String logTag) {
         mApnType = apnType;
         mState = DataConnectionTracker.State.IDLE;
         setReason(Phone.REASON_DATA_ENABLED);
-        pendingAction = PENDING_ACTION_NONE;
+        mPendingAction = PENDING_ACTION_NONE;
+        mDataEnabled = false;
+        mDependencyMet = true;
         LOG_TAG = logTag;
     }
 
     public int getPendingAction() {
-        return pendingAction;
+        return mPendingAction;
     }
 
     public void setPendingAction(int pa) {
-        pendingAction = pa;
+        mPendingAction = pa;
     }
 
     public String getApnType() {
         return mApnType;
     }
 
-    public GsmDataConnection getDataConnection() {
+    public DataConnection getDataConnection() {
         return mDataConnection;
     }
 
-    public void setDataConnection(GsmDataConnection dataConnection) {
+    public void setDataConnection(DataConnection dataConnection) {
         mDataConnection = dataConnection;
     }
 
@@ -160,6 +175,34 @@ public class ApnContext {
         return mReconnectIntent;
     }
 
+    public boolean isReady() {
+        return mDataEnabled && mDependencyMet;
+    }
+
+    public void setEnabled(boolean enabled) {
+        if (DBG) {
+            log("set enabled as " + enabled + ", for type " +
+                    mApnType + ", current state is " + mDataEnabled);
+        }
+        mDataEnabled = enabled;
+    }
+
+    public boolean isEnabled() {
+        return mDataEnabled;
+    }
+
+    public void setDependencyMet(boolean met) {
+        if (DBG) {
+            log("set mDependencyMet as " + met + ", for type " + mApnType +
+                    ", current state is " + mDependencyMet);
+        }
+        mDependencyMet = met;
+    }
+
+    public boolean getDependencyMet() {
+       return mDependencyMet;
+    }
+
     protected void log(String s) {
         Log.d(LOG_TAG, "[ApnContext] " + s);
     }
index e21e951..7214cf6 100644 (file)
@@ -1097,4 +1097,8 @@ public abstract class DataConnection extends HierarchicalStateMachine {
     public ApnSetting getApn() {
         return mApn;
     }
+
+    public int getCid() {
+        return cid;
+    }
 }
index fba73fb..d5b65e1 100644 (file)
@@ -28,6 +28,7 @@ import android.net.LinkProperties;
 import android.net.NetworkInfo;
 import android.net.wifi.WifiManager;
 import android.os.AsyncResult;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
 import android.os.Messenger;
@@ -122,6 +123,7 @@ public abstract class DataConnectionTracker extends Handler {
     protected static final int EVENT_RESET_DONE = 38;
     public static final int CMD_SET_DATA_ENABLE = 39;
     public static final int EVENT_CLEAN_UP_ALL_CONNECTIONS = 40;
+    public static final int CMD_SET_DEPENDENCY_MET = 41;
 
     /***** Constants *****/
 
@@ -139,6 +141,8 @@ public abstract class DataConnectionTracker extends Handler {
     public static final int DISABLED = 0;
     public static final int ENABLED = 1;
 
+    public static final String APN_TYPE_KEY = "apnType";
+
     // responds to the setInternalDataEnabled call - used internally to turn off data
     // for example during emergency calls
     protected boolean mInternalDataEnabled = true;
@@ -541,6 +545,19 @@ public abstract class DataConnectionTracker extends Handler {
                 break;
             }
 
+            case CMD_SET_DEPENDENCY_MET: {
+                log("CMD_SET_DEPENDENCY_MET msg=" + msg);
+                boolean met = (msg.arg1 == ENABLED) ? true : false;
+                Bundle bundle = msg.getData();
+                if (bundle != null) {
+                    String apnType = (String)bundle.get(APN_TYPE_KEY);
+                    if (apnType != null) {
+                        onSetDependencyMet(apnType, met);
+                    }
+                }
+                break;
+            }
+
             default:
                 Log.e("DATA", "Unidentified event = " + msg.what);
                 break;
@@ -810,7 +827,7 @@ public abstract class DataConnectionTracker extends Handler {
         }
     }
 
-    private void setEnabled(int id, boolean enable) {
+    protected void setEnabled(int id, boolean enable) {
         if (DBG) {
             log("setEnabled(" + id + ", " + enable + ") with old state = " + dataEnabled[id]
                     + " and enabledCount = " + enabledCount);
@@ -821,7 +838,7 @@ public abstract class DataConnectionTracker extends Handler {
         sendMessage(msg);
     }
 
-    protected synchronized void onEnableApn(int apnId, int enabled) {
+    protected void onEnableApn(int apnId, int enabled) {
         if (DBG) {
             log("EVENT_APN_ENABLE_REQUEST apnId=" + apnId + ", apnType=" + apnIdToType(apnId) +
                     ", enabled=" + enabled + ", dataEnabled = " + dataEnabled[apnId] +
@@ -829,9 +846,11 @@ public abstract class DataConnectionTracker extends Handler {
                     isApnTypeActive(apnIdToType(apnId)));
         }
         if (enabled == ENABLED) {
-            if (!dataEnabled[apnId]) {
-                dataEnabled[apnId] = true;
-                enabledCount++;
+            synchronized (this) {
+                if (!dataEnabled[apnId]) {
+                    dataEnabled[apnId] = true;
+                    enabledCount++;
+                }
             }
             String type = apnIdToType(apnId);
             if (!isApnTypeActive(type)) {
@@ -842,12 +861,16 @@ public abstract class DataConnectionTracker extends Handler {
             }
         } else {
             // disable
-            if (dataEnabled[apnId]) {
-                dataEnabled[apnId] = false;
-                enabledCount--;
-                if (enabledCount == 0) {
-                    onCleanUpConnection(true, apnId, Phone.REASON_DATA_DISABLED);
+            boolean didDisable = false;
+            synchronized (this) {
+                if (dataEnabled[apnId]) {
+                    dataEnabled[apnId] = false;
+                    enabledCount--;
+                    didDisable = true;
                 }
+            }
+            if (didDisable && enabledCount == 0) {
+                onCleanUpConnection(true, apnId, Phone.REASON_DATA_DISABLED);
 
                 // send the disconnect msg manually, since the normal route wont send
                 // it (it's not enabled)
@@ -961,6 +984,10 @@ public abstract class DataConnectionTracker extends Handler {
         }
     }
 
+    protected void onSetDependencyMet(String apnType, boolean met) {
+    }
+
+
     protected void resetAllRetryCounts() {
         for (DataConnection dc : mDataConnections.values()) {
             dc.resetRetryCount();
index 7450047..9f16d31 100644 (file)
@@ -175,6 +175,8 @@ public interface Phone {
     static final String REASON_PS_RESTRICT_DISABLED = "psRestrictDisabled";
     static final String REASON_SIM_LOADED = "simLoaded";
     static final String REASON_NW_TYPE_CHANGED = "nwTypeChanged";
+    static final String REASON_DATA_DEPENDENCY_MET = "dependencyMet";
+    static final String REASON_DATA_DEPENDENCY_UNMET = "dependencyUnmet";
 
     // Used for band mode selection methods
     static final int BM_UNSPECIFIED = 0; // selected by baseband automatically
index b0b2ac5..2589de4 100644 (file)
@@ -117,11 +117,6 @@ public class GsmDataConnection extends DataConnection {
         return mProfileId;
     }
 
-    public int getCid() {
-        // 'cid' has been defined in parent class
-        return cid;
-    }
-
     public void setActiveApnType(String apnType) {
         mActiveApnType = apnType;
     }
index 891a237..b5dadf6 100644 (file)
@@ -25,11 +25,13 @@ import android.content.Intent;
 import android.content.SharedPreferences;
 import android.database.ContentObserver;
 import android.database.Cursor;
+import android.net.ConnectivityManager;
 import android.net.ProxyProperties;
 import android.net.TrafficStats;
 import android.net.Uri;
 import android.net.LinkCapabilities;
 import android.net.LinkProperties;
+import android.net.NetworkConfig;
 import android.os.AsyncResult;
 import android.os.Message;
 import android.os.SystemClock;
@@ -164,9 +166,8 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
         p.getContext().getContentResolver().registerContentObserver(
                 Telephony.Carriers.CONTENT_URI, true, mApnObserver);
 
-        /** Create the default connection */
         mApnContexts = new ConcurrentHashMap<String, ApnContext>();
-        initApncontextsAndDataConnection();
+        initApnContextsAndDataConnection();
         broadcastMessenger();
     }
 
@@ -206,6 +207,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
      * because the phone is out of coverage or some like reason.</li>
      * </ul>
      * @return {@code true} if data connectivity is possible, {@code false} otherwise.
+     * TODO - do per-apn notifications of availability using dependencyMet values.
      */
     @Override
     protected boolean isDataPossible() {
@@ -227,14 +229,57 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
         return INTENT_RECONNECT_ALARM;
     }
 
-    protected void initApncontextsAndDataConnection() {
+    private ApnContext addApnContext(String type) {
+        ApnContext apnContext = new ApnContext(type, LOG_TAG);
+        apnContext.setDependencyMet(false);
+        mApnContexts.put(type, apnContext);
+        return apnContext;
+    }
+
+    protected void initApnContextsAndDataConnection() {
         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mPhone.getContext());
         boolean defaultEnabled = !sp.getBoolean(PhoneBase.DATA_DISABLED_ON_BOOT_KEY, false);
-        // create default type context only if enabled
-        if (defaultEnabled) {
-            ApnContext apnContext = new ApnContext(Phone.APN_TYPE_DEFAULT, LOG_TAG);
-            mApnContexts.put(apnContext.getApnType(), apnContext);
-            createDataConnection(Phone.APN_TYPE_DEFAULT);
+        // Load device network attributes from resources
+        String[] networkConfigStrings = mPhone.getContext().getResources().getStringArray(
+                com.android.internal.R.array.networkAttributes);
+        for (String networkConfigString : networkConfigStrings) {
+            NetworkConfig networkConfig = new NetworkConfig(networkConfigString);
+            ApnContext apnContext = null;
+
+            switch (networkConfig.type) {
+            case ConnectivityManager.TYPE_MOBILE:
+                apnContext = addApnContext(Phone.APN_TYPE_DEFAULT);
+                apnContext.setEnabled(defaultEnabled);
+                break;
+            case ConnectivityManager.TYPE_MOBILE_MMS:
+                apnContext = addApnContext(Phone.APN_TYPE_MMS);
+                break;
+            case ConnectivityManager.TYPE_MOBILE_SUPL:
+                apnContext = addApnContext(Phone.APN_TYPE_SUPL);
+                break;
+            case ConnectivityManager.TYPE_MOBILE_DUN:
+                apnContext = addApnContext(Phone.APN_TYPE_DUN);
+                break;
+            case ConnectivityManager.TYPE_MOBILE_HIPRI:
+                apnContext = addApnContext(Phone.APN_TYPE_HIPRI);
+                break;
+            case ConnectivityManager.TYPE_MOBILE_FOTA:
+                apnContext = addApnContext(Phone.APN_TYPE_FOTA);
+                break;
+            case ConnectivityManager.TYPE_MOBILE_IMS:
+                apnContext = addApnContext(Phone.APN_TYPE_IMS);
+                break;
+            case ConnectivityManager.TYPE_MOBILE_CBS:
+                apnContext = addApnContext(Phone.APN_TYPE_CBS);
+                break;
+            default:
+                // skip unknown types
+                continue;
+            }
+            if (apnContext != null) {
+                // set the prop, but also apply the newly set enabled and dependency values
+                onSetDependencyMet(apnContext.getApnType(), networkConfig.dependencyMet);
+            }
         }
     }
 
@@ -271,7 +316,9 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
         Iterator<ApnContext> it = mApnContexts.values().iterator();
         while (it.hasNext()) {
             ApnContext apnContext = it.next();
+            if (apnContext.isReady()) {
                 result.add(apnContext.getApnType());
+            }
         }
 
         return (String[])result.toArray(new String[0]);
@@ -353,24 +400,12 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
     public synchronized int enableApnType(String apnType) {
         if (DBG) log("calling enableApnType with type:" + apnType);
 
-        if (!isApnTypeAvailable(apnType)) {
+        ApnContext apnContext = mApnContexts.get(apnType);
+        if (apnContext == null || !isApnTypeAvailable(apnType)) {
             if (DBG) log("type not available");
             return Phone.APN_TYPE_NOT_AVAILABLE;
         }
 
-        ApnContext apnContext = mApnContexts.get(apnType);
-        if (apnContext==null) {
-            // Is there a Proxy type for this?
-            apnContext = getProxyActiveApnType(apnType);
-            if (apnContext != null ) {
-                notifyApnIdUpToCurrent(Phone.REASON_APN_SWITCHED, apnContext, apnType);
-                return Phone.APN_REQUEST_STARTED;
-            }
-            apnContext = new ApnContext(apnType, LOG_TAG);
-            if (DBG) log("New apn type context for type "+apnType);
-            mApnContexts.put(apnType, apnContext);
-        }
-
         // If already active, return
         log("enableApnType(" + apnType + ")" + ", mState(" + apnContext.getState() + ")");
 
@@ -389,24 +424,11 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
         }
 
         if (DBG) log("new apn request for type " + apnType + " is to be handled");
-        sendMessage(obtainMessage(EVENT_ENABLE_NEW_APN, apnContext));
+        setEnabled(apnTypeToId(apnType), true);
         if (DBG) log("return APN_REQUEST_STARTED");
         return Phone.APN_REQUEST_STARTED;
     }
 
-    // Returns for ex: if HIGHPRI is supported by DEFAULT
-    public ApnContext getProxyActiveApnType(String type) {
-
-        Iterator<ApnContext> it = mApnContexts.values().iterator();
-
-        while(it.hasNext()) {
-            ApnContext apnContext = it.next();
-            if (apnContext.getApnSetting() != null && mActiveApn.canHandleType(type))
-            return apnContext;
-        }
-        return null;
-    }
-
     // A new APN has gone active and needs to send events to catch up with the
     // current condition
     private void notifyApnIdUpToCurrent(String reason, ApnContext apnContext, String type) {
@@ -437,6 +459,8 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
             if (apnContext.getState() != State.IDLE && apnContext.getState() != State.FAILED) {
                 Message msg = obtainMessage(EVENT_CLEAN_UP_CONNECTION);
                 msg.arg1 = 1; // tearDown is true;
+                // TODO - don't set things on apnContext from public functions.
+                // Maybe pass reason as arg2?
                 apnContext.setReason(Phone.REASON_DATA_DISABLED);
                 msg.obj = apnContext;
                 sendMessage(msg);
@@ -487,16 +511,11 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
      */
     @Override
     public synchronized boolean getAnyDataEnabled() {
-        Iterator<ApnContext> it = mApnContexts.values().iterator();
-
         if (!(mInternalDataEnabled && mDataEnabled)) return false;
-        if (mApnContexts.isEmpty()) return false;
-        while (it.hasNext()) {
-            ApnContext apnContext= it.next();
+        for (ApnContext apnContext : mApnContexts.values()) {
             // Make sure we dont have a context that going down
             // and is explicitly disabled.
-            if (!(apnContext.getState() == State.DISCONNECTING
-                    && apnContext.getPendingAction() == ApnContext.PENDING_ACTION_APN_DISABLE)) {
+            if (isDataAllowed(apnContext)) {
                 return true;
             }
         }
@@ -508,7 +527,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
                 && apnContext.getPendingAction() == ApnContext.PENDING_ACTION_APN_DISABLE) {
             return false;
         }
-        return isDataAllowed();
+        return apnContext.isReady() && isDataAllowed();
     }
 
     //****** Called from ServiceStateTracker
@@ -532,11 +551,13 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
         } else {
             // Only check for default APN state
             ApnContext defaultApnContext = mApnContexts.get(Phone.APN_TYPE_DEFAULT);
-            if (defaultApnContext.getState() == State.FAILED) {
-                cleanUpConnection(false, defaultApnContext);
-                defaultApnContext.getDataConnection().resetRetryCount();
+            if (defaultApnContext != null) {
+                if (defaultApnContext.getState() == State.FAILED) {
+                    cleanUpConnection(false, defaultApnContext);
+                    defaultApnContext.getDataConnection().resetRetryCount();
+                }
+                trySetupData(Phone.REASON_GPRS_ATTACHED, Phone.APN_TYPE_DEFAULT);
             }
-            trySetupData(Phone.REASON_GPRS_ATTACHED, Phone.APN_TYPE_DEFAULT);
         }
     }
 
@@ -599,10 +620,11 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
 
     private boolean trySetupData(ApnContext apnContext) {
 
-        if (DBG)
+        if (DBG) {
             log("trySetupData for type:" + apnContext.getApnType() +
-                " due to " + apnContext.getReason());
-        log("[DSAC DEB] " + "trySetupData with mIsPsRestricted=" + mIsPsRestricted);
+                    " due to " + apnContext.getReason());
+            log("[DSAC DEB] " + "trySetupData with mIsPsRestricted=" + mIsPsRestricted);
+        }
 
         if (mPhone.getSimulatedRadioControl() != null) {
             // Assume data is connected on the simulator
@@ -656,12 +678,8 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
         if (mAvailability == availability) return;
         mAvailability = availability;
 
-        Iterator<ApnContext> it = mApnContexts.values().iterator();
-        while (it.hasNext()) {
-            ApnContext apnContext = it.next();
-            // FIXME: Dont understand why this needs to be done!!
-            // This information is not available (DISABLED APNS)
-            if (false) {
+        for (ApnContext apnContext : mApnContexts.values()) {
+            if (!apnContext.isReady()) {
                 if (DBG) log("notify disconnected for type:" + apnContext.getApnType());
                 mPhone.notifyDataConnection(reason != null ? reason : apnContext.getReason(),
                                             apnContext.getApnType(),
@@ -738,10 +756,10 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
             return;
         }
 
-        GsmDataConnection conn = apnContext.getDataConnection();
+        DataConnection conn = apnContext.getDataConnection();
         if (conn != null) {
             apnContext.setState(State.DISCONNECTING);
-            if (tearDown ) {
+            if (tearDown) {
                 Message msg = obtainMessage(EVENT_DISCONNECT_DONE, apnContext);
                 conn.disconnect(apnContext.getReason(), msg);
             } else {
@@ -750,10 +768,6 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
                 mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
             }
         }
-
-        if (apnContext.getPendingAction() == ApnContext.PENDING_ACTION_APN_DISABLE) {
-           mApnContexts.remove(apnContext.getApnType());
-        }
     }
 
 
@@ -853,6 +867,10 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
         }
 
         if (dc == null) {
+            dc = createDataConnection(apnContext);
+        }
+
+        if (dc == null) {
             if (DBG) log("setupData: No free GsmDataConnection found!");
             return false;
         }
@@ -1272,42 +1290,98 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
 
     private void onRecordsLoaded() {
         createAllApnList();
-        ApnContext defaultApnContext = mApnContexts.get(Phone.APN_TYPE_DEFAULT);
-        if (defaultApnContext!=null ) {
-            defaultApnContext.setReason(Phone.REASON_SIM_LOADED);
-            if (defaultApnContext.getState() == State.FAILED) {
-                if (DBG) log("onRecordsLoaded clean connection");
-                cleanUpConnection(false, defaultApnContext);
+        for (ApnContext apnContext : mApnContexts.values()) {
+            if (apnContext.isReady()) {
+                apnContext.setReason(Phone.REASON_SIM_LOADED);
+                if (apnContext.getState() == State.FAILED) {
+                    if (DBG) {
+                        log("onRecordsLoaded clean connection for " + apnContext.getApnType());
+                    }
+                    cleanUpConnection(false, apnContext);
+                }
+                sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA, apnContext));
             }
-            sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA,defaultApnContext ));
         }
     }
 
-    protected void onEnableNewApn(ApnContext apnContext ) {
-        // change our retry manager to use the appropriate numbers for the new APN
-        log("onEnableNewApn with ApnContext E");
-        if (apnContext.getApnType().equals(Phone.APN_TYPE_DEFAULT)) {
-            log("onEnableNewApn default type");
-            ApnContext defaultApnContext = mApnContexts.get(Phone.APN_TYPE_DEFAULT);
-            defaultApnContext.getDataConnection().resetRetryCount();
-        } else if (mApnToDataConnectionId.get(apnContext.getApnType()) == null) {
-            log("onEnableNewApn ApnType=" + apnContext.getApnType() +
-                    " missing, make a new connection");
-            int id = createDataConnection(apnContext.getApnType());
-            mDataConnections.get(id).resetRetryCount();
+    @Override
+    protected void onSetDependencyMet(String apnType, boolean met) {
+        ApnContext apnContext = mApnContexts.get(apnType);
+        if (apnContext == null) {
+            log("ApnContext not found in onSetDependencyMet(" + apnType + ", " + met + ")");
+            return;
+        }
+        applyNewState(apnContext, apnContext.isEnabled(), met);
+    }
+
+    private void applyNewState(ApnContext apnContext, boolean enabled, boolean met) {
+        boolean cleanup = false;
+        boolean trySetup = false;
+        if (DBG) {
+            log("applyNewState(" + apnContext.getApnType() + ", " + enabled +
+                    "(" + apnContext.isEnabled() + "), " + met + "(" +
+                    apnContext.getDependencyMet() +"))");
+        }
+        if (apnContext.isReady()) {
+            if (enabled && met) return;
+            if (!enabled) {
+                apnContext.setReason(Phone.REASON_DATA_DISABLED);
+            } else {
+                apnContext.setReason(Phone.REASON_DATA_DEPENDENCY_UNMET);
+            }
+            cleanup = true;
         } else {
-            log("oneEnableNewApn connection already exists, nothing to setup");
+            if (enabled && met) {
+                if (apnContext.isEnabled()) {
+                    apnContext.setReason(Phone.REASON_DATA_DEPENDENCY_MET);
+                } else {
+                    apnContext.setReason(Phone.REASON_DATA_ENABLED);
+                }
+                DataConnection conn = checkForConnectionForApnContext(apnContext);
+                if (conn == null) {
+                    if (apnContext.getState() == State.FAILED) {
+                        apnContext.setState(State.IDLE);
+                    }
+                    trySetup = true;
+                } else {
+                    // TODO send notifications
+                    if (DBG) {
+                        log("Found existing connection for " + apnContext.getApnType() +
+                                ": " + conn);
+                    }
+                    apnContext.setDataConnection(conn);
+                }
+            }
+        }
+        apnContext.setEnabled(enabled);
+        apnContext.setDependencyMet(met);
+        if (cleanup) cleanUpConnection(true, apnContext);
+        if (trySetup) trySetupData(apnContext);
+    }
+
+    private DataConnection checkForConnectionForApnContext(ApnContext apnContext) {
+        // Loop through all apnContexts looking for one with a conn that satisfies this apnType
+        String apnType = apnContext.getApnType();
+        for (ApnContext c : mApnContexts.values()) {
+            DataConnection conn = c.getDataConnection();
+            if (conn != null) {
+                ApnSetting apnSetting = c.getApnSetting();
+                if (apnSetting != null && apnSetting.canHandleType(apnType)) return conn;
+            }
         }
+        return null;
+    }
 
-        // TODO:  To support simultaneous PDP contexts, this should really only call
-        // cleanUpConnection if it needs to free up a GsmDataConnection.
-        if (DBG) log("onEnableNewApn setup data");
-        if (apnContext.getState() == State.FAILED) {
-            if (DBG) log("previous state is FAILED, reset to IDLE");
-            apnContext.setState(State.IDLE);
+    @Override
+    protected void onEnableApn(int apnId, int enabled) {
+        ApnContext apnContext = mApnContexts.get(apnIdToType(apnId));
+        if (apnContext == null) {
+            log("ApnContext not found in onEnableApn(" + apnId + ", " + enabled + ")");
+            return;
         }
-        trySetupData(apnContext);
-        log("onEnableNewApn with ApnContext X");
+        // TODO change our retry manager to use the appropriate numbers for the new APN
+        log("onEnableApn with ApnContext E");
+        applyNewState(apnContext, enabled == ENABLED, apnContext.getDependencyMet());
     }
 
     @Override
@@ -1392,7 +1466,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
             mLinkProperties = getLinkProperties(apnContext.getDataConnection());
             mLinkCapabilities = getLinkCapabilities(apnContext.getDataConnection());
 
-            ApnSetting apn = apnContext.getDataConnection().getApn();
+            ApnSetting apn = apnContext.getApnSetting();
             if (apn.proxy != null && apn.proxy.length() != 0) {
                 try {
                     ProxyProperties proxy = new ProxyProperties(apn.proxy,
@@ -1508,8 +1582,8 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
 
         // Check if APN disabled.
         if (apnContext.getPendingAction() == ApnContext.PENDING_ACTION_APN_DISABLE) {
-           mApnContexts.remove(apnContext.getApnType());
-           return;
+           apnContext.setEnabled(false);
+           apnContext.setPendingAction(ApnContext.PENDING_ACTION_NONE);
         }
 
         if (TextUtils.equals(apnContext.getApnType(), Phone.APN_TYPE_DEFAULT)
@@ -1553,10 +1627,12 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
         } else {
             // reset reconnect timer
             ApnContext defaultApnContext = mApnContexts.get(Phone.APN_TYPE_DEFAULT);
-            defaultApnContext.getDataConnection().resetRetryCount();
-            mReregisterOnReconnectFailure = false;
-            // in case data setup was attempted when we were on a voice call
-            trySetupData(Phone.REASON_VOICE_CALL_ENDED, Phone.APN_TYPE_DEFAULT);
+            if (defaultApnContext != null) {
+                defaultApnContext.getDataConnection().resetRetryCount();
+                mReregisterOnReconnectFailure = false;
+                // in case data setup was attempted when we were on a voice call
+                trySetupData(Phone.REASON_VOICE_CALL_ENDED, Phone.APN_TYPE_DEFAULT);
+            }
         }
     }
 
@@ -1584,9 +1660,11 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
         Iterator<ApnContext> it = mApnContexts.values().iterator();
         while (it.hasNext()) {
             ApnContext apnContext = it.next();
-            if (DBG) log("notify for type:"+apnContext.getApnType());
-            mPhone.notifyDataConnection(reason != null ? reason : apnContext.getReason(),
-                    apnContext.getApnType());
+            if (apnContext.isReady()) {
+                if (DBG) log("notify for type:"+apnContext.getApnType());
+                mPhone.notifyDataConnection(reason != null ? reason : apnContext.getReason(),
+                        apnContext.getApnType());
+            }
         }
         notifyDataAvailability(reason);
     }
@@ -1598,7 +1676,6 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
     private void createAllApnList() {
         mAllApns = new ArrayList<ApnSetting>();
         String operator = mPhone.mSIMRecords.getSIMOperatorNumeric();
-
         if (operator != null) {
             String selection = "numeric = '" + operator + "'";
             if (DBG) log("createAllApnList: selection=" + selection);
@@ -1631,7 +1708,8 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
     }
 
     /** Return the id for a new data connection */
-    private int createDataConnection(String apnType) {
+    private GsmDataConnection createDataConnection(ApnContext apnContext) {
+        String apnType = apnContext.getApnType();
         log("createDataConnection(" + apnType + ") E");
         RetryManager rm = new RetryManager();
 
@@ -1656,12 +1734,13 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
         }
 
         int id = mUniqueIdGenerator.getAndIncrement();
-        DataConnection conn = GsmDataConnection.makeDataConnection(mPhone, id, rm);
+        GsmDataConnection conn = GsmDataConnection.makeDataConnection(mPhone, id, rm);
+        conn.resetRetryCount();
         mDataConnections.put(id, conn);
-        mApnToDataConnectionId.put(apnType, id);
+        apnContext.setDataConnection(conn);
 
         log("createDataConnection(" + apnType + ") X id=" + id);
-        return id;
+        return conn;
     }
 
     private void destroyDataConnections() {
@@ -1691,7 +1770,6 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
         }
 
         String operator = mPhone.mSIMRecords.getSIMOperatorNumeric();
-
         if (requestedApnType.equals(Phone.APN_TYPE_DEFAULT)) {
             if (canSetPreferApn && mPreferredApn != null) {
                 log("Preferred APN:" + operator + ":"
@@ -1707,13 +1785,14 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
                 }
             }
         }
-
         if (mAllApns != null) {
             for (ApnSetting apn : mAllApns) {
                 if (apn.canHandleType(requestedApnType)) {
                     apnList.add(apn);
                 }
             }
+        } else {
+            loge("mAllApns is empty!");
         }
         if (DBG) log("buildWaitingApns: X apnList=" + apnList);
         return apnList;
@@ -1797,14 +1876,6 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
                 onRecordsLoaded();
                 break;
 
-        case EVENT_ENABLE_NEW_APN:
-                ApnContext apnContext = null;
-                if (msg.obj instanceof ApnContext) {
-                    apnContext = (ApnContext)msg.obj;
-                }
-                onEnableNewApn(apnContext);
-                break;
-
             case EVENT_DATA_CONNECTION_DETACHED:
                 onDataConnectionDetached();
                 break;
@@ -1883,8 +1954,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
                 if (msg.obj instanceof ApnContext) {
                     cleanUpConnection(tearDown, (ApnContext)msg.obj);
                 } else {
-                    Log.e(LOG_TAG,
-                          "[GsmDataConnectionTracker] connectpion cleanup request w/o apn context");
+                    loge("[GsmDataConnectionTracker] connectpion cleanup request w/o apn context");
                 }
                 break;
             default:
index 07900ae..338cb4d 100644 (file)
@@ -50,6 +50,7 @@ public class WifiStateTracker implements NetworkStateTracker {
     private LinkProperties mLinkProperties;
     private LinkCapabilities mLinkCapabilities;
     private NetworkInfo mNetworkInfo;
+    private NetworkInfo.State mLastState = NetworkInfo.State.UNKNOWN;
 
     /* For sending events to connectivity service handler */
     private Handler mCsHandler;
@@ -217,6 +218,14 @@ public class WifiStateTracker implements NetworkStateTracker {
                 if (mLinkCapabilities == null) {
                     mLinkCapabilities = new LinkCapabilities();
                 }
+                // don't want to send redundent state messages
+                // TODO can this be fixed in WifiStateMachine?
+                NetworkInfo.State state = mNetworkInfo.getState();
+                if (mLastState == state) {
+                    return;
+                } else {
+                    mLastState = state;
+                }
                 Message msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
                 msg.sendToTarget();
             } else if (intent.getAction().equals(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION)) {
@@ -228,4 +237,7 @@ public class WifiStateTracker implements NetworkStateTracker {
         }
     }
 
+    public void setDependencyMet(boolean met) {
+        // not supported on this network
+    }
 }