Provide a way to override the avoid bad wifi configuration

ConnectivityManager.setAvoidUnvalidated only works if the
config_networkAvoidBadWifi configuration is set to 0 and the
NETWORK_AVOID_BAD_WIFI setting is unset. There is no easy way
for a testing app to temporary set a test value to verify the
behavior of the API. Thus, add a mechanism to allow test app
to set a period of time to temporary unstrict the resource
configuration, i.e. Temporary simulate config_networkAvoidBadWifi
configured to 0.

Bug: 186061922
Test: atest CtsNetTestCases FrameworksNetTests
Change-Id: If772078c61a9b12926f104d5dfc9c9071e844732
diff --git a/framework/src/android/net/ConnectivityManager.java b/framework/src/android/net/ConnectivityManager.java
index 20f3853..badf2c1 100644
--- a/framework/src/android/net/ConnectivityManager.java
+++ b/framework/src/android/net/ConnectivityManager.java
@@ -4704,6 +4704,22 @@
     }
 
     /**
+     * Temporarily allow bad wifi to override {@code config_networkAvoidBadWifi} configuration.
+     *
+     * @param timeMs The expired current time. The value should be set within a limited time from
+     *               now.
+     *
+     * @hide
+     */
+    public void setTestAllowBadWifiUntil(long timeMs) {
+        try {
+            mService.setTestAllowBadWifiUntil(timeMs);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Requests that the system open the captive portal app on the specified network.
      *
      * <p>This is to be used on networks where a captive portal was detected, as per
diff --git a/framework/src/android/net/IConnectivityManager.aidl b/framework/src/android/net/IConnectivityManager.aidl
index c434bbc..50ec781 100644
--- a/framework/src/android/net/IConnectivityManager.aidl
+++ b/framework/src/android/net/IConnectivityManager.aidl
@@ -226,4 +226,6 @@
     void offerNetwork(int providerId, in NetworkScore score,
             in NetworkCapabilities caps, in INetworkOfferCallback callback);
     void unofferNetwork(in INetworkOfferCallback callback);
+
+    void setTestAllowBadWifiUntil(long timeMs);
 }
diff --git a/framework/src/android/net/util/MultinetworkPolicyTracker.java b/framework/src/android/net/util/MultinetworkPolicyTracker.java
index 0b42a00..7e62d28 100644
--- a/framework/src/android/net/util/MultinetworkPolicyTracker.java
+++ b/framework/src/android/net/util/MultinetworkPolicyTracker.java
@@ -75,6 +75,7 @@
     private volatile boolean mAvoidBadWifi = true;
     private volatile int mMeteredMultipathPreference;
     private int mActiveSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+    private volatile long mTestAllowBadWifiUntilMs = 0;
 
     // Mainline module can't use internal HandlerExecutor, so add an identical executor here.
     private static class HandlerExecutor implements Executor {
@@ -162,14 +163,31 @@
      * Whether the device or carrier configuration disables avoiding bad wifi by default.
      */
     public boolean configRestrictsAvoidBadWifi() {
+        final boolean allowBadWifi = mTestAllowBadWifiUntilMs > 0
+                && mTestAllowBadWifiUntilMs > System.currentTimeMillis();
+        // If the config returns true, then avoid bad wifi design can be controlled by the
+        // NETWORK_AVOID_BAD_WIFI setting.
+        if (allowBadWifi) return true;
+
         // TODO: use R.integer.config_networkAvoidBadWifi directly
         final int id = mResources.get().getIdentifier("config_networkAvoidBadWifi",
                 "integer", mResources.getResourcesContext().getPackageName());
         return (getResourcesForActiveSubId().getInteger(id) == 0);
     }
 
+    /**
+     * Temporarily allow bad wifi to override {@code config_networkAvoidBadWifi} configuration.
+     * The value works when the time set is more than {@link System.currentTimeMillis()}.
+     */
+    public void setTestAllowBadWifiUntil(long timeMs) {
+        Log.d(TAG, "setTestAllowBadWifiUntil: " + mTestAllowBadWifiUntilMs);
+        mTestAllowBadWifiUntilMs = timeMs;
+        updateAvoidBadWifi();
+    }
+
+    @VisibleForTesting
     @NonNull
-    private Resources getResourcesForActiveSubId() {
+    protected Resources getResourcesForActiveSubId() {
         return SubscriptionManager.getResourcesForSubId(
                 mResources.getResourcesContext(), mActiveSubId);
     }