Merge "[NS D02] Mix in the ignore on wifi policy."
diff --git a/core/java/android/net/NetworkScore.java b/core/java/android/net/NetworkScore.java
index ae17378..d2e59eb 100644
--- a/core/java/android/net/NetworkScore.java
+++ b/core/java/android/net/NetworkScore.java
@@ -21,7 +21,6 @@
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
-import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -87,7 +86,7 @@
         /** toString */
         public String toString() {
             return "latency = " + latencyMs + " downlinkBandwidth = " + downlinkBandwidthKBps
-                    + "uplinkBandwidth = " + uplinkBandwidthKBps;
+                    + " uplinkBandwidth = " + uplinkBandwidthKBps;
         }
 
         @NonNull
@@ -354,17 +353,27 @@
         private Metrics mLinkLayerMetrics = new Metrics(Metrics.LATENCY_UNKNOWN,
                 Metrics.BANDWIDTH_UNKNOWN, Metrics.BANDWIDTH_UNKNOWN);
         @NonNull
-        private Metrics mEndToMetrics = new Metrics(Metrics.LATENCY_UNKNOWN,
+        private Metrics mEndToEndMetrics = new Metrics(Metrics.LATENCY_UNKNOWN,
                 Metrics.BANDWIDTH_UNKNOWN, Metrics.BANDWIDTH_UNKNOWN);
         private int mSignalStrength = UNKNOWN_SIGNAL_STRENGTH;
         private int mRange = RANGE_UNKNOWN;
         private boolean mExiting = false;
         private int mLegacyScore = 0;
-        @NonNull private Bundle mExtensions = new Bundle();
 
         /** Create a new builder. */
         public Builder() { }
 
+        /** @hide */
+        public Builder(@NonNull final NetworkScore source) {
+            mPolicy = source.mPolicy;
+            mLinkLayerMetrics = source.mLinkLayerMetrics;
+            mEndToEndMetrics = source.mEndToEndMetrics;
+            mSignalStrength = source.mSignalStrength;
+            mRange = source.mRange;
+            mExiting = source.mExiting;
+            mLegacyScore = source.mLegacyScore;
+        }
+
         /** Add a policy flag. */
         @NonNull public Builder addPolicy(@Policy final int policy) {
             mPolicy |= policy;
@@ -385,7 +394,7 @@
 
         /** Set the end-to-end metrics. */
         @NonNull public Builder setEndToEndMetrics(@NonNull final Metrics endToEndMetrics) {
-            mEndToMetrics = endToEndMetrics;
+            mEndToEndMetrics = endToEndMetrics;
             return this;
         }
 
@@ -417,7 +426,7 @@
 
         /** Build the NetworkScore object represented by this builder. */
         @NonNull public NetworkScore build() {
-            return new NetworkScore(mPolicy, mLinkLayerMetrics, mEndToMetrics,
+            return new NetworkScore(mPolicy, mLinkLayerMetrics, mEndToEndMetrics,
                     mSignalStrength, mRange, mExiting, mLegacyScore);
         }
     }
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 60a30d3..7dab90d 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -3817,8 +3817,9 @@
         return avoidBadWifi();
     }
 
-
     private void rematchForAvoidBadWifiUpdate() {
+        ensureRunningOnConnectivityServiceThread();
+        mixInAllNetworkScores();
         rematchAllNetworksAndRequests();
         for (NetworkAgentInfo nai: mNetworkAgentInfos.values()) {
             if (nai.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
@@ -7035,9 +7036,45 @@
         }
     }
 
+    /**
+     * Re-mixin all network scores.
+     * This is called when some global setting like avoidBadWifi has changed.
+     * TODO : remove this when all usages have been removed.
+     */
+    private void mixInAllNetworkScores() {
+        ensureRunningOnConnectivityServiceThread();
+        for (final NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
+            nai.setNetworkScore(mixInNetworkScore(nai, nai.getNetworkScore()));
+        }
+    }
+
+    /**
+     * Mix in the Connectivity-managed parts of the NetworkScore.
+     * @param nai The NAI this score applies to.
+     * @param sourceScore the score sent by the network agent, or the previous score of this NAI.
+     * @return A new score with the Connectivity-managed parts mixed in.
+     */
+    @NonNull
+    private NetworkScore mixInNetworkScore(@NonNull final NetworkAgentInfo nai,
+            @NonNull final NetworkScore sourceScore) {
+        final NetworkScore.Builder score = new NetworkScore.Builder(sourceScore);
+
+        // TODO : this should be done in Telephony. It should be handled per-network because
+        // it's a carrier-dependent config.
+        if (nai.networkCapabilities.hasTransport(TRANSPORT_CELLULAR)) {
+            if (mMultinetworkPolicyTracker.getAvoidBadWifi()) {
+                score.clearPolicy(NetworkScore.POLICY_IGNORE_ON_WIFI);
+            } else {
+                score.addPolicy(NetworkScore.POLICY_IGNORE_ON_WIFI);
+            }
+        }
+
+        return score.build();
+    }
+
     private void updateNetworkScore(NetworkAgentInfo nai, NetworkScore ns) {
         if (VDBG || DDBG) log("updateNetworkScore for " + nai.toShortString() + " to " + ns);
-        nai.setNetworkScore(ns);
+        nai.setNetworkScore(mixInNetworkScore(nai, ns));
         rematchAllNetworksAndRequests();
         sendUpdatedScoreToFactories(nai);
     }
diff --git a/tests/net/common/java/android/net/NetworkScoreTest.kt b/tests/net/common/java/android/net/NetworkScoreTest.kt
index a63d58d..3e10992 100644
--- a/tests/net/common/java/android/net/NetworkScoreTest.kt
+++ b/tests/net/common/java/android/net/NetworkScoreTest.kt
@@ -17,6 +17,9 @@
 package android.net
 
 import android.net.NetworkScore.Metrics.BANDWIDTH_UNKNOWN
+import android.net.NetworkScore.POLICY_DEFAULT_SUBSCRIPTION
+import android.net.NetworkScore.POLICY_IGNORE_ON_WIFI
+import android.net.NetworkScore.RANGE_MEDIUM
 import androidx.test.filters.SmallTest
 import androidx.test.runner.AndroidJUnit4
 import com.android.testutils.assertParcelSane
@@ -39,19 +42,19 @@
         assertEquals(TEST_SCORE, builder.build().getLegacyScore())
         assertParcelSane(builder.build(), 7)
 
-        builder.addPolicy(NetworkScore.POLICY_IGNORE_ON_WIFI)
-                .addPolicy(NetworkScore.POLICY_DEFAULT_SUBSCRIPTION)
+        builder.addPolicy(POLICY_IGNORE_ON_WIFI)
+                .addPolicy(POLICY_DEFAULT_SUBSCRIPTION)
                 .setLinkLayerMetrics(NetworkScore.Metrics(44 /* latency */,
                         380 /* downlinkBandwidth */, BANDWIDTH_UNKNOWN /* uplinkBandwidth */))
                 .setEndToEndMetrics(NetworkScore.Metrics(11 /* latency */,
                         BANDWIDTH_UNKNOWN /* downlinkBandwidth */, 100_000 /* uplinkBandwidth */))
                 .setRange(NetworkScore.RANGE_MEDIUM)
         assertParcelSane(builder.build(), 7)
-        builder.clearPolicy(NetworkScore.POLICY_IGNORE_ON_WIFI)
+        builder.clearPolicy(POLICY_IGNORE_ON_WIFI)
         val ns = builder.build()
         assertParcelSane(ns, 7)
-        assertFalse(ns.hasPolicy(NetworkScore.POLICY_IGNORE_ON_WIFI))
-        assertTrue(ns.hasPolicy(NetworkScore.POLICY_DEFAULT_SUBSCRIPTION))
+        assertFalse(ns.hasPolicy(POLICY_IGNORE_ON_WIFI))
+        assertTrue(ns.hasPolicy(POLICY_DEFAULT_SUBSCRIPTION))
 
         val exitingNs = ns.withExiting(true)
         assertNotEquals(ns.isExiting, exitingNs.isExiting)
@@ -73,4 +76,17 @@
         assertTrue(builder1.build().equals(builder2.build()))
         assertEquals(builder1.build().hashCode(), builder2.build().hashCode())
     }
+
+    @Test
+    fun testBuilderEquals() {
+        val ns = NetworkScore.Builder()
+                .addPolicy(POLICY_IGNORE_ON_WIFI)
+                .addPolicy(POLICY_DEFAULT_SUBSCRIPTION)
+                .setExiting(true)
+                .setEndToEndMetrics(NetworkScore.Metrics(145, 2500, 1430))
+                .setRange(RANGE_MEDIUM)
+                .setSignalStrength(400)
+                .build()
+        assertEquals(ns, NetworkScore.Builder(ns).build())
+    }
 }