Merge changes from topic "peruidcallback-cts"

* changes:
  Cleanups to VPN hostside tests.
  Ensure the HostsideVpnTests passes with keyguard locked.
  Add CTS tests for registerDefaultNetworkCallbackAsUid.
diff --git a/tests/cts/hostside/app/Android.bp b/tests/cts/hostside/app/Android.bp
index f351b47..112b9eb 100644
--- a/tests/cts/hostside/app/Android.bp
+++ b/tests/cts/hostside/app/Android.bp
@@ -27,6 +27,7 @@
         "androidx.test.rules",
         "androidx.test.ext.junit",
         "compatibility-device-util-axt",
+        "cts-net-utils",
         "ctstestrunner-axt",
         "ub-uiautomator",
         "CtsHostsideNetworkTestsAidl",
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyActivity.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyActivity.java
index 0d0bc58..55eec11 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyActivity.java
+++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyActivity.java
@@ -17,6 +17,7 @@
 package com.android.cts.net.hostside;
 
 import android.app.Activity;
+import android.app.KeyguardManager;
 import android.content.Intent;
 import android.os.Bundle;
 import android.view.WindowManager;
@@ -34,6 +35,11 @@
         getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
                 | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
                 | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
+
+        // Dismiss the keyguard so that the tests can click on the VPN confirmation dialog.
+        // FLAG_DISMISS_KEYGUARD is not sufficient to do this because as soon as the dialog appears,
+        // this activity goes into the background and the keyguard reappears.
+        getSystemService(KeyguardManager.class).requestDismissKeyguard(this, null /* callback */);
     }
 
     @Override
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java
index 9b437e6..c0600e7 100755
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java
+++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java
@@ -61,6 +61,7 @@
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.SystemProperties;
+import android.os.UserHandle;
 import android.provider.Settings;
 import android.support.test.uiautomator.UiDevice;
 import android.support.test.uiautomator.UiObject;
@@ -76,6 +77,7 @@
 
 import com.android.compatibility.common.util.BlockingBroadcastReceiver;
 import com.android.modules.utils.build.SdkLevel;
+import com.android.testutils.TestableNetworkCallback;
 
 import java.io.Closeable;
 import java.io.FileDescriptor;
@@ -92,6 +94,7 @@
 import java.net.UnknownHostException;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
+import java.util.List;
 import java.util.Objects;
 import java.util.Random;
 import java.util.concurrent.CompletableFuture;
@@ -698,34 +701,6 @@
         setAndVerifyPrivateDns(initialMode);
     }
 
-    private class NeverChangeNetworkCallback extends NetworkCallback {
-        private CountDownLatch mLatch = new CountDownLatch(1);
-        private volatile Network mFirstNetwork;
-        private volatile Network mOtherNetwork;
-
-        public void onAvailable(Network n) {
-            // Don't assert here, as it crashes the test with a hard to debug message.
-            if (mFirstNetwork == null) {
-                mFirstNetwork = n;
-                mLatch.countDown();
-            } else if (mOtherNetwork == null) {
-                mOtherNetwork = n;
-            }
-        }
-
-        public Network getFirstNetwork() throws Exception {
-            assertTrue(
-                    "System default callback got no network after " + TIMEOUT_MS + "ms. "
-                    + "Please ensure the device has a working Internet connection.",
-                    mLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
-            return mFirstNetwork;
-        }
-
-        public void assertNeverChanged() {
-            assertNull(mOtherNetwork);
-        }
-    }
-
     public void testDefault() throws Exception {
         if (!supportedHardware()) return;
         // If adb TCP port opened, this test may running by adb over network.
@@ -741,13 +716,24 @@
                 getInstrumentation().getTargetContext(), MyVpnService.ACTION_ESTABLISHED);
         receiver.register();
 
-        // Expect the system default network not to change.
-        final NeverChangeNetworkCallback neverChangeCallback = new NeverChangeNetworkCallback();
+        // Test the behaviour of a variety of types of network callbacks.
         final Network defaultNetwork = mCM.getActiveNetwork();
+        final TestableNetworkCallback systemDefaultCallback = new TestableNetworkCallback();
+        final TestableNetworkCallback otherUidCallback = new TestableNetworkCallback();
+        final TestableNetworkCallback myUidCallback = new TestableNetworkCallback();
         if (SdkLevel.isAtLeastS()) {
-            runWithShellPermissionIdentity(() ->
-                    mCM.registerSystemDefaultNetworkCallback(neverChangeCallback,
-                            new Handler(Looper.getMainLooper())), NETWORK_SETTINGS);
+            final int otherUid = UserHandle.getUid(UserHandle.of(5), Process.FIRST_APPLICATION_UID);
+            final Handler h = new Handler(Looper.getMainLooper());
+            runWithShellPermissionIdentity(() -> {
+                mCM.registerSystemDefaultNetworkCallback(systemDefaultCallback, h);
+                mCM.registerDefaultNetworkCallbackAsUid(otherUid, otherUidCallback, h);
+                mCM.registerDefaultNetworkCallbackAsUid(Process.myUid(), myUidCallback, h);
+            }, NETWORK_SETTINGS);
+            for (TestableNetworkCallback callback :
+                    List.of(systemDefaultCallback, otherUidCallback, myUidCallback)) {
+                callback.expectAvailableCallbacks(defaultNetwork, false /* suspended */,
+                        true /* validated */, false /* blocked */, TIMEOUT_MS);
+            }
         }
 
         FileDescriptor fd = openSocketFdInOtherApp(TEST_HOST, 80, TIMEOUT_MS);
@@ -767,20 +753,24 @@
 
         checkTrafficOnVpn();
 
-        maybeExpectVpnTransportInfo(mCM.getActiveNetwork());
+        final Network vpnNetwork = mCM.getActiveNetwork();
+        myUidCallback.expectAvailableThenValidatedCallbacks(vpnNetwork, TIMEOUT_MS);
+        assertEquals(vpnNetwork, mCM.getActiveNetwork());
+        assertNotEqual(defaultNetwork, vpnNetwork);
+        maybeExpectVpnTransportInfo(vpnNetwork);
 
-        assertNotEqual(defaultNetwork, mCM.getActiveNetwork());
         if (SdkLevel.isAtLeastS()) {
             // Check that system default network callback has not seen any network changes, even
-            // though the app's default network changed. This needs to be done before testing
-            // private DNS because checkStrictModePrivateDns will set the private DNS server to
-            // a nonexistent name, which will cause validation to fail and cause the default
-            // network to switch (e.g., from wifi to cellular).
-            assertEquals(defaultNetwork, neverChangeCallback.getFirstNetwork());
-            neverChangeCallback.assertNeverChanged();
-            runWithShellPermissionIdentity(
-                    () -> mCM.unregisterNetworkCallback(neverChangeCallback),
-                    NETWORK_SETTINGS);
+            // though the app's default network changed. Also check that otherUidCallback saw no
+            // network changes, because otherUid is in a different user and not subject to the VPN.
+            // This needs to be done before testing  private DNS because checkStrictModePrivateDns
+            // will set the private DNS server to a nonexistent name, which will cause validation to
+            // fail and could cause the default network to switch (e.g., from wifi to cellular).
+            systemDefaultCallback.assertNoCallback();
+            otherUidCallback.assertNoCallback();
+            mCM.unregisterNetworkCallback(systemDefaultCallback);
+            mCM.unregisterNetworkCallback(otherUidCallback);
+            mCM.unregisterNetworkCallback(myUidCallback);
         }
 
         checkStrictModePrivateDns();
diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
index 096f656..18f0588 100644
--- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -111,6 +111,7 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.MessageQueue;
+import android.os.Process;
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.VintfRuntimeInfo;
@@ -587,12 +588,14 @@
         final TestNetworkCallback defaultTrackingCallback = new TestNetworkCallback();
         mCm.registerDefaultNetworkCallback(defaultTrackingCallback);
 
-        final TestNetworkCallback systemDefaultTrackingCallback = new TestNetworkCallback();
+        final TestNetworkCallback systemDefaultCallback = new TestNetworkCallback();
+        final TestNetworkCallback perUidCallback = new TestNetworkCallback();
+        final Handler h = new Handler(Looper.getMainLooper());
         if (shouldTestSApis()) {
-            runWithShellPermissionIdentity(() ->
-                    mCmShim.registerSystemDefaultNetworkCallback(systemDefaultTrackingCallback,
-                            new Handler(Looper.getMainLooper())),
-                    NETWORK_SETTINGS);
+            runWithShellPermissionIdentity(() -> {
+                mCmShim.registerSystemDefaultNetworkCallback(systemDefaultCallback, h);
+                mCmShim.registerDefaultNetworkCallbackAsUid(Process.myUid(), perUidCallback, h);
+            }, NETWORK_SETTINGS);
         }
 
         Network wifiNetwork = null;
@@ -607,22 +610,27 @@
             assertNotNull("Did not receive onAvailable for TRANSPORT_WIFI request",
                     wifiNetwork);
 
+            final Network defaultNetwork = defaultTrackingCallback.waitForAvailable();
             assertNotNull("Did not receive onAvailable on default network callback",
-                    defaultTrackingCallback.waitForAvailable());
+                    defaultNetwork);
 
             if (shouldTestSApis()) {
                 assertNotNull("Did not receive onAvailable on system default network callback",
-                        systemDefaultTrackingCallback.waitForAvailable());
+                        systemDefaultCallback.waitForAvailable());
+                final Network perUidNetwork = perUidCallback.waitForAvailable();
+                assertNotNull("Did not receive onAvailable on per-UID default network callback",
+                        perUidNetwork);
+                assertEquals(defaultNetwork, perUidNetwork);
             }
+
         } catch (InterruptedException e) {
             fail("Broadcast receiver or NetworkCallback wait was interrupted.");
         } finally {
             mCm.unregisterNetworkCallback(callback);
             mCm.unregisterNetworkCallback(defaultTrackingCallback);
             if (shouldTestSApis()) {
-                runWithShellPermissionIdentity(
-                        () -> mCm.unregisterNetworkCallback(systemDefaultTrackingCallback),
-                        NETWORK_SETTINGS);
+                mCm.unregisterNetworkCallback(systemDefaultCallback);
+                mCm.unregisterNetworkCallback(perUidCallback);
             }
         }
     }