Add NetworkAgent event for ExplicitlySelected

Lets Wifi tell us when the user selected this AP vs auto-connected.

bug:17396168
Change-Id: I6e067ab62ed49040629aa31fe07ff880d3d542f0
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
index 95e24ac..b83198d 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -132,6 +132,13 @@
     public static final int VALID_NETWORK = 1;
     public static final int INVALID_NETWORK = 2;
 
+     /**
+     * Sent by the NetworkAgent to ConnectivityService to indicate this network was
+     * explicitly selected.  This should be sent before the NetworkInfo is marked
+     * CONNECTED so it can be given special treatment at that time.
+     */
+    public static final int EVENT_SET_EXPLICITLY_SELECTED = BASE + 10;
+
     public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni,
             NetworkCapabilities nc, LinkProperties lp, int score) {
         this(looper, context, logTag, ni, nc, lp, score, null);
@@ -281,6 +288,15 @@
     }
 
     /**
+     * Called by the bearer to indicate this network was manually selected by the user.
+     * This should be called before the NetworkInfo is marked CONNECTED so that this
+     * Network can be given special treatment at that time.
+     */
+    public void explicitlySelected() {
+        queueOrSendMessage(EVENT_SET_EXPLICITLY_SELECTED, 0);
+    }
+
+    /**
      * Called when ConnectivityService has indicated they no longer want this network.
      * The parent factory should (previously) have received indication of the change
      * as well, either canceling NetworkRequests or altering their score such that this
diff --git a/core/java/android/net/NetworkMisc.java b/core/java/android/net/NetworkMisc.java
index 34f6cf4..5d2a43d 100644
--- a/core/java/android/net/NetworkMisc.java
+++ b/core/java/android/net/NetworkMisc.java
@@ -25,12 +25,32 @@
  * @hide
  */
 public class NetworkMisc implements Parcelable {
+
     /**
      * If the {@link Network} is a VPN, whether apps are allowed to bypass the VPN. This is set by
      * a {@link VpnService} and used by {@link ConnectivityService} when creating a VPN.
      */
     public boolean allowBypass;
 
+    /**
+     * Set if the network was manually/explicitly connected to by the user either from settings
+     * or a 3rd party app.  For example, turning on cell data is not explicit but tapping on a wifi
+     * ap in the wifi settings to trigger a connection is explicit.  A 3rd party app asking to
+     * connect to a particular access point is also explicit, though this may change in the future
+     * as we want apps to use the multinetwork apis.
+     */
+    public boolean explicitlySelected;
+
+    public NetworkMisc() {
+    }
+
+    public NetworkMisc(NetworkMisc nm) {
+        if (nm != null) {
+            allowBypass = nm.allowBypass;
+            explicitlySelected = nm.explicitlySelected;
+        }
+    }
+
     @Override
     public int describeContents() {
         return 0;
@@ -39,6 +59,7 @@
     @Override
     public void writeToParcel(Parcel out, int flags) {
         out.writeInt(allowBypass ? 1 : 0);
+        out.writeInt(explicitlySelected ? 1 : 0);
     }
 
     public static final Creator<NetworkMisc> CREATOR = new Creator<NetworkMisc>() {
@@ -46,6 +67,7 @@
         public NetworkMisc createFromParcel(Parcel in) {
             NetworkMisc networkMisc = new NetworkMisc();
             networkMisc.allowBypass = in.readInt() != 0;
+            networkMisc.explicitlySelected = in.readInt() != 0;
             return networkMisc;
         }
 
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index c2d92f3..dfec307 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1925,6 +1925,15 @@
                     }
                     break;
                 }
+                case NetworkAgent.EVENT_SET_EXPLICITLY_SELECTED: {
+                    NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo);
+                    if (nai == null) {
+                        loge("EVENT_SET_EXPLICITLY_SELECTED from unknown NetworkAgent");
+                        break;
+                    }
+                    nai.networkMisc.explicitlySelected = true;
+                    break;
+                }
                 case NetworkMonitor.EVENT_NETWORK_TESTED: {
                     NetworkAgentInfo nai = (NetworkAgentInfo)msg.obj;
                     if (isLiveNetworkAgent(nai, "EVENT_NETWORK_VALIDATED")) {
@@ -4250,7 +4259,7 @@
         NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(),
             new NetworkInfo(networkInfo), new LinkProperties(linkProperties),
             new NetworkCapabilities(networkCapabilities), currentScore, mContext, mTrackerHandler,
-            networkMisc);
+            new NetworkMisc(networkMisc));
         synchronized (this) {
             nai.networkMonitor.systemReady = mSystemReady;
         }
@@ -4552,8 +4561,10 @@
         for (NetworkRequestInfo nri : mNetworkRequests.values()) {
             NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(nri.request.requestId);
             if (newNetwork == currentNetwork) {
-                if (DBG) log("Network " + newNetwork.name() + " was already satisfying" +
-                              " request " + nri.request.requestId + ". No change.");
+                if (DBG) {
+                    log("Network " + newNetwork.name() + " was already satisfying" +
+                            " request " + nri.request.requestId + ". No change.");
+                }
                 keep = true;
                 continue;
             }
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 957d705..15ffc0d 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -53,6 +53,9 @@
     // Penalty applied to scores of Networks that have not been validated.
     private static final int UNVALIDATED_SCORE_PENALTY = 40;
 
+    // Score for explicitly connected network.
+    private static final int EXPLICITLY_SELECTED_NETWORK_SCORE = 100;
+
     // The list of NetworkRequests being satisfied by this Network.
     public final SparseArray<NetworkRequest> networkRequests = new SparseArray<NetworkRequest>();
     public final ArrayList<NetworkRequest> networkLingered = new ArrayList<NetworkRequest>();
@@ -95,9 +98,10 @@
         int score = currentScore;
 
         if (!validated) score -= UNVALIDATED_SCORE_PENALTY;
-
         if (score < 0) score = 0;
 
+        if (networkMisc.explicitlySelected) score = EXPLICITLY_SELECTED_NETWORK_SCORE;
+
         return score;
     }
 
@@ -110,7 +114,8 @@
                 network + "}  lp{" +
                 linkProperties + "}  nc{" +
                 networkCapabilities + "}  Score{" + getCurrentScore() + "} " +
-                "validated{" + validated + "} created{" + created + "} }";
+                "validated{" + validated + "} created{" + created + "} " +
+                "explicitlySelected{" + networkMisc.explicitlySelected + "} }";
     }
 
     public String name() {