Improved connectivity check by also asserting NetworkInfo states.

BUG: 28473659
BUG: 26571724
Change-Id: Iba687003431ed5c353412268726967a798f538da
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
index ce9d970..08df9e1 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
+++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
@@ -25,13 +25,14 @@
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.TimeUnit;
 
-import android.app.ActivityManager;
 import android.app.Instrumentation;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.net.ConnectivityManager;
 import android.net.NetworkInfo;
+import android.net.NetworkInfo.DetailedState;
+import android.net.NetworkInfo.State;
 import android.net.wifi.WifiManager;
 import android.test.InstrumentationTestCase;
 import android.util.Log;
@@ -61,8 +62,7 @@
     private static final String EXTRA_RECEIVER_NAME =
             "com.android.cts.net.hostside.app2.extra.RECEIVER_NAME";
     private static final String RESULT_SEPARATOR = ";";
-    private static final String STATUS_NETWORK_UNAVAILABLE_PREFIX = "NetworkUnavailable:";
-    private static final String STATUS_NETWORK_AVAILABLE_PREFIX = "NetworkAvailable:";
+    private static final String NETWORK_STATUS_SEPARATOR = "\\|";
     private static final int SECOND_IN_MS = 1000;
     private static final int NETWORK_TIMEOUT_MS = 15 * SECOND_IN_MS;
     private static final int PROCESS_STATE_FOREGROUND_SERVICE = 4;
@@ -144,7 +144,7 @@
         }, null, 0, null, null);
 
         final String resultData = result.poll(timeoutMs, TimeUnit.MILLISECONDS);
-        Log.d(TAG, "Ordered broadcast response: " + resultData);
+        Log.d(TAG, "Ordered broadcast response after " + timeoutMs + "ms: " + resultData );
         return resultData;
     }
 
@@ -206,17 +206,30 @@
     }
 
     private void assertNetworkStatus(boolean expectAvailable, String status) throws Exception {
-        if (status == null) {
-            Log.d(TAG, "timeout waiting for ordered broadcast");
-            if (expectAvailable) {
-                fail("did not get network status when access was allowed");
-            }
-            return;
+        assertNotNull("timeout waiting for ordered broadcast", status);
+
+        // Network status format is described on MyBroadcastReceiver.checkNetworkStatus()
+        final String[] parts = status.split(NETWORK_STATUS_SEPARATOR);
+        assertEquals("Wrong network status: " + status, 5, parts.length); // Sanity check
+        final State state = State.valueOf(parts[0]);
+        final DetailedState detailedState = DetailedState.valueOf(parts[1]);
+        final boolean connected = Boolean.valueOf(parts[2]);
+        final String connectionCheckDetails = parts[3];
+        final String networkInfo = parts[4];
+
+        if (expectAvailable) {
+            assertTrue("should be connected: " + connectionCheckDetails
+                    + " (network info: " + networkInfo + ")", connected);
+            assertEquals("wrong state for " + networkInfo, State.CONNECTED, state);
+            assertEquals("wrong detailed state for " + networkInfo,
+                    DetailedState.CONNECTED, detailedState);
+        } else {
+            assertFalse("should not be connected: " + connectionCheckDetails
+                    + " (network info: " + networkInfo + ")", connected);
+            assertEquals("wrong state for " + networkInfo, State.DISCONNECTED, state);
+            assertEquals("wrong detailed state for " + networkInfo,
+                    DetailedState.BLOCKED, detailedState);
         }
-        final String expectedPrefix = expectAvailable ?
-                STATUS_NETWORK_AVAILABLE_PREFIX : STATUS_NETWORK_UNAVAILABLE_PREFIX;
-        assertTrue("Wrong network status (" + status + ") when expectedAvailable is "
-                + expectAvailable, status.startsWith(expectedPrefix));
     }
 
     protected String executeShellCommand(String command) throws Exception {
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeTest.java
index d1217b4..e5466cd 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeTest.java
+++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeTest.java
@@ -42,6 +42,7 @@
 
     public void testBackgroundNetworkAccess_enabled() throws Exception {
         setPowerSaveMode(true);
+
         assertBackgroundNetworkAccess(false);
 
         // Make sure app is allowed if running a foreground service.
diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java
index 668669b..d247c31 100644
--- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java
+++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java
@@ -17,7 +17,6 @@
 
 import android.content.Context;
 import android.content.pm.PackageManager.NameNotFoundException;
-import android.util.Log;
 
 public final class Common {
 
@@ -37,8 +36,6 @@
     static final String EXTRA_RECEIVER_NAME =
             "com.android.cts.net.hostside.app2.extra.RECEIVER_NAME";
     static final char RESULT_SEPARATOR = ';';
-    static final String STATUS_NETWORK_UNAVAILABLE_PREFIX = "NetworkUnavailable:";
-    static final String STATUS_NETWORK_AVAILABLE_PREFIX = "NetworkAvailable:";
 
     static int getUid(Context context) {
         final String packageName = context.getPackageName();
diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java
index 07f717b..e8a959c 100644
--- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java
+++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java
@@ -24,8 +24,6 @@
 import static com.android.cts.net.hostside.app2.Common.EXTRA_RECEIVER_NAME;
 import static com.android.cts.net.hostside.app2.Common.MANIFEST_RECEIVER;
 import static com.android.cts.net.hostside.app2.Common.RESULT_SEPARATOR;
-import static com.android.cts.net.hostside.app2.Common.STATUS_NETWORK_AVAILABLE_PREFIX;
-import static com.android.cts.net.hostside.app2.Common.STATUS_NETWORK_UNAVAILABLE_PREFIX;
 import static com.android.cts.net.hostside.app2.Common.TAG;
 import static com.android.cts.net.hostside.app2.Common.getUid;
 
@@ -125,6 +123,38 @@
         setResultData(data.toString());
     }
 
+
+    private static final String NETWORK_STATUS_TEMPLATE = "%s|%s|%s|%s|%s";
+
+    /**
+     * Checks whether the network is available and return a string which can then be send as a
+     * result data for the ordered broadcast.
+     *
+     * <p>
+     * The string has the following format:
+     *
+     * <p><pre><code>
+     * NetinfoState|NetinfoDetailedState|RealConnectionCheck|RealConnectionCheckDetails|Netinfo
+     * </code></pre>
+     *
+     * <p>Where:
+     *
+     * <ul>
+     * <li>{@code NetinfoState}: enum value of {@link NetworkInfo.State}.
+     * <li>{@code NetinfoDetailedState}: enum value of {@link NetworkInfo.DetailedState}.
+     * <li>{@code RealConnectionCheck}: boolean value of a real connection check (i.e., an attempt
+     *     to access an external website.
+     * <li>{@code RealConnectionCheckDetails}: if HTTP output core or exception string of the real
+     *     connection attempt
+     * <li>{@code Netinfo}: string representation of the {@link NetworkInfo}.
+     * </ul>
+     *
+     * For example, if the connection was established fine, the result would be something like:
+     * <p><pre><code>
+     * CONNECTED|CONNECTED|true|200|[type: WIFI[], state: CONNECTED/CONNECTED, reason: ...]
+     * </code></pre>
+     *
+     */
     private String checkNetworkStatus(final Context context, final ConnectivityManager cm)
             throws InterruptedException {
         final LinkedBlockingQueue<String> result = new LinkedBlockingQueue<>(1);
@@ -138,24 +168,29 @@
                 Log.d(TAG, "Running checkNetworkStatus() on thread "
                         + Thread.currentThread().getName() + " for UID " + getUid(context)
                         + "\n\tactiveNetworkInfo: " + networkInfo + "\n\tURL: " + address);
-                String prefix = STATUS_NETWORK_AVAILABLE_PREFIX;
+                boolean checkStatus = false;
+                String checkDetails = "N/A";
                 try {
                     final URL url = new URL(address);
                     final HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                     conn.setReadTimeout(NETWORK_TIMEOUT_MS);
-                    conn.setConnectTimeout(NETWORK_TIMEOUT_MS);
+                    conn.setConnectTimeout(NETWORK_TIMEOUT_MS / 2);
                     conn.setRequestMethod("GET");
                     conn.setDoInput(true);
                     conn.connect();
                     final int response = conn.getResponseCode();
-                    Log.d(TAG, "HTTP response for " + address + ": " + response);
+                    checkStatus = true;
+                    checkDetails = "HTTP response for " + address + ": " + response;
                 } catch (Exception e) {
-                    Log.d(TAG, "Exception getting " + address + ": " + e);
-                    prefix = STATUS_NETWORK_UNAVAILABLE_PREFIX + "Exception " + e + ":";
+                    checkStatus = false;
+                    checkDetails = "Exception getting " + address + ": " + e;
                 }
-                final String netInfo = prefix + networkInfo;
-                Log.d(TAG, "Offering " + netInfo);
-                result.offer(netInfo);
+                Log.d(TAG, checkDetails);
+                final String status = String.format(NETWORK_STATUS_TEMPLATE,
+                        networkInfo.getState().name(), networkInfo.getDetailedState().name(),
+                        Boolean.toString(checkStatus), checkDetails, networkInfo);
+                Log.d(TAG, "Offering " + status);
+                result.offer(status);
             }
         }, mName).start();
         return result.poll(NETWORK_TIMEOUT_MS * 2, TimeUnit.MILLISECONDS);
diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java
index ca535bc..435e201 100644
--- a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java
+++ b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java
@@ -104,17 +104,17 @@
         assertPowerSaveModeWhitelist(TEST_PKG, false);
     }
 
-    public void testBatteryBatterySaverModeNonMeteredTest_disabled() throws Exception {
+    public void testBatterySaverModeNonMetered_disabled() throws Exception {
         runDeviceTests(TEST_PKG, TEST_PKG + ".BatterySaverModeNonMeteredTest",
                 "testBackgroundNetworkAccess_disabled");
     }
 
-    public void testBatteryBatterySaverModeNonMeteredTest_whitelisted() throws Exception {
+    public void testBatterySaverModeNonMeteredt_whitelisted() throws Exception {
         runDeviceTests(TEST_PKG, TEST_PKG + ".BatterySaverModeNonMeteredTest",
                 "testBackgroundNetworkAccess_whitelisted");
     }
 
-    public void testBatteryBatterySaverModeNonMeteredTest_enabled() throws Exception {
+    public void testBatterySaverModeNonMetered_enabled() throws Exception {
         runDeviceTests(TEST_PKG, TEST_PKG + ".BatterySaverModeNonMeteredTest",
                 "testBackgroundNetworkAccess_enabled");
     }