Covers more corner cases on restricted network modes:

- Tests what happens on foreground applications when a restriction (like
  Data Saver or Battery Saver modes) is turned on (prior tests would
  turn the restriction on *before* switching the app to foreground).
- Tests multiple restrictions simultaneously enabled.

Also improved existing code:

- Fixed background state check.
- Reused some common checks in helper methods.
- Retries checks for process state.

BUG: 28473659

Change-Id: Ifcf9cc6d895ccde0ab5177f9f5d8c347ce53b811
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 3ee2f68..f2a69f2 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
@@ -176,34 +176,90 @@
         assertNetworkAccess(true);
     }
 
+    protected void assertForegroundServiceNetworkAccess() throws Exception {
+        assertForegroundServiceState(); // Sanity check.
+        assertNetworkAccess(true);
+    }
+
+    /**
+     * Asserts that an app always have access while on foreground or running a foreground service.
+     *
+     * <p>This method will launch an activity and a foreground service to make the assertion, but
+     * will finish the activity / stop the service afterwards.
+     */
+    protected void assertsForegroundAlwaysHasNetworkAccess() throws Exception{
+        // Checks foreground first.
+        launchActivity();
+        assertForegroundNetworkAccess();
+        finishActivity();
+
+        // Then foreground service
+        startForegroundService();
+        assertForegroundServiceNetworkAccess();
+        stopForegroundService();
+    }
+
     protected final void assertBackgroundState() throws Exception {
-        final ProcessState state = getProcessStateByUid(mUid);
-        Log.v(TAG, "assertBackgroundState(): status for app2 (" + mUid + "): " + state);
-        final boolean isBackground = isBackground(state.state);
-        assertTrue("App2 is not on background state: " + state, isBackground);
+        final int maxTries = 30;
+        ProcessState state = null;
+        for (int i = 1; i <= maxTries; i++) {
+            state = getProcessStateByUid(mUid);
+            Log.v(TAG, "assertBackgroundState(): status for app2 (" + mUid + ") on attempt #" + i
+                    + ": " + state);
+            if (isBackground(state.state)) {
+                return;
+            }
+            Log.d(TAG, "App not on background state on attempt #" + i
+                    + "; sleeping 1s before trying again");
+            Thread.sleep(SECOND_IN_MS);
+        }
+        fail("App2 is not on background state after " + maxTries + " attempts: " + state );
     }
 
     protected final void assertForegroundState() throws Exception {
-        final ProcessState state = getProcessStateByUid(mUid);
-        Log.v(TAG, "assertForegroundState(): status for app2 (" + mUid + "): " + state);
-        final boolean isForeground = !isBackground(state.state);
-        assertTrue("App2 is not on foreground state: " + state, isForeground);
+        final int maxTries = 30;
+        ProcessState state = null;
+        for (int i = 1; i <= maxTries; i++) {
+            state = getProcessStateByUid(mUid);
+            Log.v(TAG, "assertForegroundState(): status for app2 (" + mUid + ") on attempt #" + i
+                    + ": " + state);
+            if (!isBackground(state.state)) {
+                return;
+            }
+            Log.d(TAG, "App not on foreground state on attempt #" + i
+                    + "; sleeping 1s before trying again");
+            Thread.sleep(SECOND_IN_MS);
+        }
+        fail("App2 is not on foreground state after " + maxTries + " attempts: " + state );
     }
 
     protected final void assertForegroundServiceState() throws Exception {
-        final ProcessState state = getProcessStateByUid(mUid);
-        Log.v(TAG, "assertForegroundServiceState(): status for app2 (" + mUid + "): " + state);
-        assertEquals("App2 is not on foreground service state: " + state,
-                PROCESS_STATE_FOREGROUND_SERVICE, state.state);
+        final int maxTries = 30;
+        ProcessState state = null;
+        for (int i = 1; i <= maxTries; i++) {
+            state = getProcessStateByUid(mUid);
+            Log.v(TAG, "assertForegroundServiceState(): status for app2 (" + mUid + ") on attempt #"
+                    + i + ": " + state);
+            if (state.state == PROCESS_STATE_FOREGROUND_SERVICE) {
+                return;
+            }
+            Log.d(TAG, "App not on foreground service state on attempt #" + i
+                    + "; sleeping 1s before trying again");
+            Thread.sleep(SECOND_IN_MS);
+        }
+        fail("App2 is not on foreground service state after " + maxTries + " attempts: " + state );
     }
 
     /**
      * Returns whether an app state should be considered "background" for restriction purposes.
      */
     protected boolean isBackground(int state) {
-        return state >= PROCESS_STATE_FOREGROUND_SERVICE;
+        return state > PROCESS_STATE_FOREGROUND_SERVICE;
     }
 
+    /**
+     * Asserts whether the active network is available or not.
+     */
     private void assertNetworkAccess(boolean expectAvailable) throws Exception {
         final Intent intent = new Intent(ACTION_CHECK_NETWORK);
 
@@ -495,13 +551,27 @@
                 "am startservice com.android.cts.net.hostside.app2/.MyForegroundService");
     }
 
+    protected void stopForegroundService() throws Exception {
+        executeShellCommand(
+                "am stopservice com.android.cts.net.hostside.app2/.MyForegroundService");
+    }
+
     /**
      * Launches an activity on app2 so its process is elevated to foreground status.
      */
-    protected void launchApp2Activity() throws Exception {
+    protected void launchActivity() throws Exception {
         executeShellCommand("am start com.android.cts.net.hostside.app2/.MyActivity");
     }
 
+    /**
+     * Finishes an activity on app2 so its process is demoted fromforeground status.
+     */
+    protected void finishActivity() throws Exception {
+        executeShellCommand("am broadcast -a "
+                + " com.android.cts.net.hostside.app2.action.FINISH_ACTIVITY "
+                + "--receiver-foreground --receiver-registered-only");
+    }
+
     private String toString(int status) {
         switch (status) {
             case RESTRICT_BACKGROUND_STATUS_DISABLED:
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java
index 5f5f80b..d1db01c 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java
+++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java
@@ -23,8 +23,10 @@
     public void setUp() throws Exception {
         super.setUp();
 
+        // Set initial state.
+        removePowerSaveModeWhitelist(TEST_APP2_PKG);
         setPowerSaveMode(false);
-        assertPowerSaveModeWhitelist(TEST_APP2_PKG, false); // Sanity check
+
         registerBroadcastReceiver();
     }
 
@@ -39,35 +41,46 @@
         setPowerSaveMode(true);
         assertBackgroundNetworkAccess(false);
 
-        // Make sure app is allowed if running a foreground service.
-        startForegroundService();
-        assertForegroundServiceState();
-        assertBackgroundNetworkAccess(true);
+        assertsForegroundAlwaysHasNetworkAccess();
+        assertBackgroundNetworkAccess(false);
 
-        // Should always have access when running on foreground
-        launchApp2Activity();
+        // Make sure foreground app doesn't lose access upon enabling it.
+        setPowerSaveMode(false);
+        launchActivity();
         assertForegroundNetworkAccess();
+        setPowerSaveMode(true);
+        assertForegroundNetworkAccess();
+        finishActivity();
+        assertBackgroundNetworkAccess(false);
+
+        // Same for foreground service.
+        setPowerSaveMode(false);
+        startForegroundService();
+        assertForegroundNetworkAccess();
+        setPowerSaveMode(true);
+        assertForegroundNetworkAccess();
+        stopForegroundService();
+        assertBackgroundNetworkAccess(false);
     }
 
     public void testBackgroundNetworkAccess_whitelisted() throws Exception {
         setPowerSaveMode(true);
         assertBackgroundNetworkAccess(false);
+
         addPowerSaveModeWhitelist(TEST_APP2_PKG);
         assertBackgroundNetworkAccess(true);
+
         removePowerSaveModeWhitelist(TEST_APP2_PKG);
         assertBackgroundNetworkAccess(false);
 
-        // Should always have access when running on foreground
-        launchApp2Activity();
-        assertForegroundNetworkAccess();
+        assertsForegroundAlwaysHasNetworkAccess();
+        assertBackgroundNetworkAccess(false);
     }
 
     public void testBackgroundNetworkAccess_disabled() throws Exception {
-        setPowerSaveMode(false);
         assertBackgroundNetworkAccess(true);
 
-        // Should always have access when running on foreground
-        launchApp2Activity();
-        assertForegroundNetworkAccess();
+        assertsForegroundAlwaysHasNetworkAccess();
+        assertBackgroundNetworkAccess(true);
     }
 }
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 539c598..22b876a 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
@@ -23,9 +23,11 @@
     public void setUp() throws Exception {
         super.setUp();
 
+        // Set initial state.
         setMeteredNetwork();
+        removePowerSaveModeWhitelist(TEST_APP2_PKG);
         setPowerSaveMode(false);
-        assertPowerSaveModeWhitelist(TEST_APP2_PKG, false); // Sanity check
+
         registerBroadcastReceiver();
     }
 
@@ -42,38 +44,48 @@
 
     public void testBackgroundNetworkAccess_enabled() throws Exception {
         setPowerSaveMode(true);
-
         assertBackgroundNetworkAccess(false);
 
-        // Make sure app is allowed if running a foreground service.
-        startForegroundService();
-        assertForegroundServiceState();
-        assertBackgroundNetworkAccess(true);
+        assertsForegroundAlwaysHasNetworkAccess();
+        assertBackgroundNetworkAccess(false);
 
-        // Should always have access when running on foreground
-        launchApp2Activity();
+        // Make sure foreground app doesn't lose access upon enabling it.
+        setPowerSaveMode(false);
+        launchActivity();
         assertForegroundNetworkAccess();
+        setPowerSaveMode(true);
+        assertForegroundNetworkAccess();
+        finishActivity();
+        assertBackgroundNetworkAccess(false);
+
+        // Same for foreground service.
+        setPowerSaveMode(false);
+        startForegroundService();
+        assertForegroundNetworkAccess();
+        setPowerSaveMode(true);
+        assertForegroundNetworkAccess();
+        stopForegroundService();
+        assertBackgroundNetworkAccess(false);
     }
 
     public void testBackgroundNetworkAccess_whitelisted() throws Exception {
         setPowerSaveMode(true);
         assertBackgroundNetworkAccess(false);
+
         addPowerSaveModeWhitelist(TEST_APP2_PKG);
         assertBackgroundNetworkAccess(true);
+
         removePowerSaveModeWhitelist(TEST_APP2_PKG);
         assertBackgroundNetworkAccess(false);
 
-        // Should always have access when running on foreground
-        launchApp2Activity();
-        assertForegroundNetworkAccess();
+        assertsForegroundAlwaysHasNetworkAccess();
+        assertBackgroundNetworkAccess(false);
     }
 
     public void testBackgroundNetworkAccess_disabled() throws Exception {
-        setPowerSaveMode(false);
         assertBackgroundNetworkAccess(true);
 
-        // Should always have access when running on foreground
-        launchApp2Activity();
-        assertForegroundNetworkAccess();
+        assertsForegroundAlwaysHasNetworkAccess();
+        assertBackgroundNetworkAccess(true);
     }
 }
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java
index 0971770..1895156 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java
+++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java
@@ -20,15 +20,6 @@
 import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED;
 import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED;
 
-/*
- * TODO: need to add more scenarios:
- * - test access on foreground app
- * - test access on foreground service app
- * - make sure it works when app is on foreground and state is transitioned:
- *   - data saver is enabled
- *   - app is added/removed to blacklist
- *
- */
 public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase {
 
     private static final String[] REQUIRED_WHITELISTED_PACKAGES = {
@@ -39,9 +30,14 @@
     public void setUp() throws Exception {
         super.setUp();
 
+        // Set initial state.
         setMeteredNetwork();
         setRestrictBackground(false);
+        removeRestrictBackgroundWhitelist(mUid);
+        removeRestrictBackgroundBlacklist(mUid);
+
         registerBroadcastReceiver();
+        assertRestrictBackgroundChangedReceived(0);
    }
 
     @Override
@@ -56,8 +52,6 @@
     }
 
     public void testGetRestrictBackgroundStatus_disabled() throws Exception {
-        removeRestrictBackgroundWhitelist(mUid);
-        assertRestrictBackgroundChangedReceived(0);
         assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_DISABLED);
 
         // Sanity check: make sure status is always disabled, never whitelisted
@@ -65,14 +59,14 @@
         assertRestrictBackgroundChangedReceived(0);
         assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_DISABLED);
 
-        // Should always have access when running on foreground
-        launchApp2Activity();
-        assertForegroundNetworkAccess();
+        assertsForegroundAlwaysHasNetworkAccess();
+        assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_DISABLED);
     }
 
     public void testGetRestrictBackgroundStatus_whitelisted() throws Exception {
         setRestrictBackground(true);
         assertRestrictBackgroundChangedReceived(1);
+        assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED);
 
         addRestrictBackgroundWhitelist(mUid);
         assertRestrictBackgroundChangedReceived(2);
@@ -80,11 +74,10 @@
 
         removeRestrictBackgroundWhitelist(mUid);
         assertRestrictBackgroundChangedReceived(3);
-        assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_ENABLED);
+        assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED);
 
-        // Should always have access when running on foreground
-        launchApp2Activity();
-        assertForegroundNetworkAccess();
+        assertsForegroundAlwaysHasNetworkAccess();
+        assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED);
     }
 
     public void testGetRestrictBackgroundStatus_enabled() throws Exception {
@@ -92,19 +85,26 @@
         assertRestrictBackgroundChangedReceived(1);
         assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED);
 
-        removeRestrictBackgroundWhitelist(mUid);
-        assertRestrictBackgroundChangedReceived(1);
+        assertsForegroundAlwaysHasNetworkAccess();
         assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED);
 
-        // Make sure app is allowed if running a foreground service.
-        assertBackgroundNetworkAccess(false);
-        startForegroundService();
-        assertForegroundServiceState();
-        assertBackgroundNetworkAccess(true);
-
-        // Should always have access when running on foreground
-        launchApp2Activity();
+        // Make sure foreground app doesn't lose access upon enabling it.
+        setRestrictBackground(false);
+        launchActivity();
         assertForegroundNetworkAccess();
+        setRestrictBackground(true);
+        assertForegroundNetworkAccess();
+        finishActivity();
+        assertBackgroundNetworkAccess(false);
+
+        // Same for foreground service.
+        setRestrictBackground(false);
+        startForegroundService();
+        assertForegroundNetworkAccess();
+        setRestrictBackground(true);
+        assertForegroundNetworkAccess();
+        stopForegroundService();
+        assertBackgroundNetworkAccess(false);
     }
 
     public void testGetRestrictBackgroundStatus_blacklisted() throws Exception {
@@ -112,6 +112,9 @@
         assertRestrictBackgroundChangedReceived(1);
         assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED);
 
+        assertsForegroundAlwaysHasNetworkAccess();
+        assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED);
+
         // Make sure blacklist prevails over whitelist.
         setRestrictBackground(true);
         assertRestrictBackgroundChangedReceived(2);
@@ -128,12 +131,8 @@
         assertRestrictBackgroundChangedReceived(5);
         assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_DISABLED);
 
-        // Should always have access when running on foreground
-        addRestrictBackgroundBlacklist(mUid);
-        assertRestrictBackgroundChangedReceived(6);
-        assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_ENABLED);
-        launchApp2Activity();
-        assertForegroundNetworkAccess();
+        assertsForegroundAlwaysHasNetworkAccess();
+        assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_DISABLED);
     }
 
     public void testGetRestrictBackgroundStatus_requiredWhitelistedPackages() throws Exception {
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java
new file mode 100644
index 0000000..140d135
--- /dev/null
+++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.cts.net.hostside;
+
+import android.util.Log;
+
+/**
+ * Test cases for the more complex scenarios where multiple restrictions (like Battery Saver Mode
+ * and Data Saver Mode) are applied simultaneously.
+ * <p>
+ * <strong>NOTE: </strong>it might sound like the test methods on this class are testing too much,
+ * which would make it harder to diagnose individual failures, but the assumption is that such
+ * failure most likely will happen when the restriction is tested individually as well.
+ */
+public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase {
+    private static final String TAG = "MixedModesTest";
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+
+        // Set initial state.
+        removeRestrictBackgroundWhitelist(mUid);
+        removeRestrictBackgroundBlacklist(mUid);
+        removePowerSaveModeWhitelist(TEST_APP2_PKG);
+
+        registerBroadcastReceiver();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+
+        try {
+            setRestrictBackground(false);
+        } finally {
+            setPowerSaveMode(false);
+        }
+    }
+
+    /**
+     * Tests all DS ON and BS ON scenarios from network-policy-restrictions.md on metered networks.
+     */
+    public void testDataAndBatterySaverModes_meteredNetwork() throws Exception {
+        Log.i(TAG, "testDataAndBatterySaverModes_meteredNetwork() tests");
+        setMeteredNetwork();
+
+        try {
+            setRestrictBackground(true);
+            setPowerSaveMode(true);
+
+            Log.v(TAG, "Not whitelisted for any.");
+            assertBackgroundNetworkAccess(false);
+            assertsForegroundAlwaysHasNetworkAccess();
+            assertBackgroundNetworkAccess(false);
+
+            Log.v(TAG, "Whitelisted for Data Saver but not for Battery Saver.");
+            addRestrictBackgroundWhitelist(mUid);
+            removePowerSaveModeWhitelist(TEST_APP2_PKG);
+            assertBackgroundNetworkAccess(false);
+            assertsForegroundAlwaysHasNetworkAccess();
+            assertBackgroundNetworkAccess(false);
+            removeRestrictBackgroundWhitelist(mUid);
+
+            Log.v(TAG, "Whitelisted for Battery Saver but not for Data Saver.");
+            addPowerSaveModeWhitelist(TEST_APP2_PKG);
+            removeRestrictBackgroundWhitelist(mUid);
+            assertBackgroundNetworkAccess(false);
+            assertsForegroundAlwaysHasNetworkAccess();
+            assertBackgroundNetworkAccess(false);
+            removePowerSaveModeWhitelist(TEST_APP2_PKG);
+
+            Log.v(TAG, "Whitelisted for both.");
+            addRestrictBackgroundWhitelist(mUid);
+            addPowerSaveModeWhitelist(TEST_APP2_PKG);
+            assertBackgroundNetworkAccess(true);
+            assertsForegroundAlwaysHasNetworkAccess();
+            assertBackgroundNetworkAccess(true);
+            removePowerSaveModeWhitelist(TEST_APP2_PKG);
+            assertBackgroundNetworkAccess(false);
+            removeRestrictBackgroundWhitelist(mUid);
+
+            Log.v(TAG, "Blacklisted for Data Saver, not whitelisted for Battery Saver.");
+            addRestrictBackgroundBlacklist(mUid);
+            removePowerSaveModeWhitelist(TEST_APP2_PKG);
+            assertBackgroundNetworkAccess(false);
+            assertsForegroundAlwaysHasNetworkAccess();
+            assertBackgroundNetworkAccess(false);
+            removeRestrictBackgroundBlacklist(mUid);
+
+            Log.v(TAG, "Blacklisted for Data Saver, whitelisted for Battery Saver.");
+            addRestrictBackgroundBlacklist(mUid);
+            addPowerSaveModeWhitelist(TEST_APP2_PKG);
+            assertBackgroundNetworkAccess(false);
+            assertsForegroundAlwaysHasNetworkAccess();
+            assertBackgroundNetworkAccess(false);
+            removeRestrictBackgroundBlacklist(mUid);
+            removePowerSaveModeWhitelist(TEST_APP2_PKG);
+        } finally {
+            resetMeteredNetwork();
+        }
+    }
+
+    /**
+     * Tests all DS ON and BS ON scenarios from network-policy-restrictions.md on non-metered
+     * networks.
+     */
+    public void testDataAndBatterySaverModes_nonMeteredNetwork() throws Exception {
+        if (mCm.isActiveNetworkMetered()) {
+            Log.w(TAG, "testDataAndBatterySaverModes_nonMeteredNetwork() skipped because network"
+                    + " is metered");
+            return;
+        }
+        Log.i(TAG, "testDataAndBatterySaverModes_nonMeteredNetwork() tests");
+        setRestrictBackground(true);
+        setPowerSaveMode(true);
+
+        Log.v(TAG, "Not whitelisted for any.");
+        assertBackgroundNetworkAccess(false);
+        assertsForegroundAlwaysHasNetworkAccess();
+        assertBackgroundNetworkAccess(false);
+
+        Log.v(TAG, "Whitelisted for Data Saver but not for Battery Saver.");
+        addRestrictBackgroundWhitelist(mUid);
+        removePowerSaveModeWhitelist(TEST_APP2_PKG);
+        assertBackgroundNetworkAccess(false);
+        assertsForegroundAlwaysHasNetworkAccess();
+        assertBackgroundNetworkAccess(false);
+        removeRestrictBackgroundWhitelist(mUid);
+
+        Log.v(TAG, "Whitelisted for Battery Saver but not for Data Saver.");
+        addPowerSaveModeWhitelist(TEST_APP2_PKG);
+        removeRestrictBackgroundWhitelist(mUid);
+        assertBackgroundNetworkAccess(true);
+        assertsForegroundAlwaysHasNetworkAccess();
+        assertBackgroundNetworkAccess(true);
+        removePowerSaveModeWhitelist(TEST_APP2_PKG);
+
+        Log.v(TAG, "Whitelisted for both.");
+        addRestrictBackgroundWhitelist(mUid);
+        addPowerSaveModeWhitelist(TEST_APP2_PKG);
+        assertBackgroundNetworkAccess(true);
+        assertsForegroundAlwaysHasNetworkAccess();
+        assertBackgroundNetworkAccess(true);
+        removePowerSaveModeWhitelist(TEST_APP2_PKG);
+        assertBackgroundNetworkAccess(false);
+        removeRestrictBackgroundWhitelist(mUid);
+
+        Log.v(TAG, "Blacklisted for Data Saver, not whitelisted for Battery Saver.");
+        addRestrictBackgroundBlacklist(mUid);
+        removePowerSaveModeWhitelist(TEST_APP2_PKG);
+        assertBackgroundNetworkAccess(false);
+        assertsForegroundAlwaysHasNetworkAccess();
+        assertBackgroundNetworkAccess(false);
+        removeRestrictBackgroundBlacklist(mUid);
+
+        Log.v(TAG, "Blacklisted for Data Saver, whitelisted for Battery Saver.");
+        addRestrictBackgroundBlacklist(mUid);
+        addPowerSaveModeWhitelist(TEST_APP2_PKG);
+        assertBackgroundNetworkAccess(true);
+        assertsForegroundAlwaysHasNetworkAccess();
+        assertBackgroundNetworkAccess(true);
+        removeRestrictBackgroundBlacklist(mUid);
+        removePowerSaveModeWhitelist(TEST_APP2_PKG);
+    }
+}
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 ed58184..d827921 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
@@ -34,10 +34,11 @@
             "com.android.cts.net.hostside.app2.action.CHECK_NETWORK";
     static final String ACTION_RECEIVER_READY =
             "com.android.cts.net.hostside.app2.action.RECEIVER_READY";
+    static final String ACTION_FINISH_ACTIVITY =
+            "com.android.cts.net.hostside.app2.action.FINISH_ACTIVITY";
     static final String EXTRA_ACTION = "com.android.cts.net.hostside.app2.extra.ACTION";
     static final String EXTRA_RECEIVER_NAME =
             "com.android.cts.net.hostside.app2.extra.RECEIVER_NAME";
-    static final char RESULT_SEPARATOR = ';';
 
     static int getUid(Context context) {
         final String packageName = context.getPackageName();
diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyActivity.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyActivity.java
index 7c6b504..444b696 100644
--- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyActivity.java
+++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyActivity.java
@@ -15,8 +15,15 @@
  */
 package com.android.cts.net.hostside.app2;
 
+import static com.android.cts.net.hostside.app2.Common.ACTION_FINISH_ACTIVITY;
 import static com.android.cts.net.hostside.app2.Common.TAG;
+
 import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
 import android.util.Log;
 
 /**
@@ -25,6 +32,18 @@
 public class MyActivity extends Activity {
 
     @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        registerReceiver(new BroadcastReceiver() {
+
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                Log.d(TAG, "Finishing MyActivity");
+                MyActivity.this.finish();
+            }}, new IntentFilter(ACTION_FINISH_ACTIVITY));
+    }
+
+    @Override
     protected void onStart() {
         super.onStart();
         Log.d(TAG, "MyActivity.onStart()");
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 b876276..114d5c1 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
@@ -17,6 +17,7 @@
 package com.android.cts.net.hostside.app2;
 
 import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED;
+
 import static com.android.cts.net.hostside.app2.Common.ACTION_CHECK_NETWORK;
 import static com.android.cts.net.hostside.app2.Common.ACTION_GET_COUNTERS;
 import static com.android.cts.net.hostside.app2.Common.ACTION_GET_RESTRICT_BACKGROUND_STATUS;
@@ -24,7 +25,6 @@
 import static com.android.cts.net.hostside.app2.Common.EXTRA_ACTION;
 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.TAG;
 import static com.android.cts.net.hostside.app2.Common.getUid;
 
diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyForegroundService.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyForegroundService.java
index bbafd4c..1afc3d6 100644
--- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyForegroundService.java
+++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyForegroundService.java
@@ -35,7 +35,7 @@
 
     @Override
     public int onStartCommand(Intent intent, int flags, int startId) {
-        Log.d(TAG, "MyForegroundService.onStartCommand: " + intent);
+        Log.d(TAG, "MyForegroundService.onStartCommand(): " + intent);
         startForeground(42, new Notification.Builder(this)
             .setSmallIcon(R.drawable.ic_dialog_alert) // any icon is fine
             .build());
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 38802d7..ec375d6 100644
--- a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java
+++ b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java
@@ -121,6 +121,16 @@
                 "testBackgroundNetworkAccess_enabled");
     }
 
+    public void testDataAndBatterySaverModes_meteredNetwork() throws Exception {
+        runDeviceTests(TEST_PKG, TEST_PKG + ".MixedModesTest",
+                "testDataAndBatterySaverModes_meteredNetwork");
+    }
+
+    public void testDataAndBatterySaverModes_nonMeteredNetwork() throws Exception {
+        runDeviceTests(TEST_PKG, TEST_PKG + ".MixedModesTest",
+                "testDataAndBatterySaverModes_nonMeteredNetwork");
+    }
+
     private void assertRestrictBackgroundWhitelist(int uid, boolean expected) throws Exception {
         final int max_tries = 5;
         boolean actual = false;