Snap for 9465878 from fea58811da97306a4364a83088bf10ae877100a3 to tm-qpr2-release

Change-Id: Ia74ad141050c67928486cd10de198eada7ff9db1
diff --git a/tests/JobScheduler/src/android/jobscheduler/cts/ConnectivityConstraintTest.java b/tests/JobScheduler/src/android/jobscheduler/cts/ConnectivityConstraintTest.java
index 00d7517..7b0d261 100644
--- a/tests/JobScheduler/src/android/jobscheduler/cts/ConnectivityConstraintTest.java
+++ b/tests/JobScheduler/src/android/jobscheduler/cts/ConnectivityConstraintTest.java
@@ -18,48 +18,25 @@
 import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
-import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
-import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
 
-import static com.android.compatibility.common.util.TestUtils.waitUntil;
-
-import android.Manifest;
 import android.annotation.TargetApi;
 import android.app.job.JobInfo;
 import android.app.job.JobParameters;
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.pm.PackageManager;
-import android.location.LocationManager;
 import android.net.ConnectivityManager;
 import android.net.Network;
 import android.net.NetworkCapabilities;
 import android.net.NetworkRequest;
-import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiManager;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
 import android.platform.test.annotations.RequiresDevice;
 import android.provider.Settings;
 import android.util.Log;
 
 import com.android.compatibility.common.util.AppStandbyUtils;
 import com.android.compatibility.common.util.BatteryUtils;
-import com.android.compatibility.common.util.CallbackAsserter;
-import com.android.compatibility.common.util.ShellIdentityUtils;
 import com.android.compatibility.common.util.SystemUtil;
 
-import junit.framework.AssertionFailedError;
-
-import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
 /**
  * Schedules jobs with the {@link android.app.job.JobScheduler} that have network connectivity
  * constraints.
@@ -70,18 +47,13 @@
 @RequiresDevice // Emulators don't always have access to wifi/network
 public class ConnectivityConstraintTest extends BaseJobSchedulerTest {
     private static final String TAG = "ConnectivityConstraintTest";
-    private static final String RESTRICT_BACKGROUND_GET_CMD =
-            "cmd netpolicy get restrict-background";
-    private static final String RESTRICT_BACKGROUND_ON_CMD =
-            "cmd netpolicy set restrict-background true";
-    private static final String RESTRICT_BACKGROUND_OFF_CMD =
-            "cmd netpolicy set restrict-background false";
 
     /** Unique identifier for the job scheduled by this suite of tests. */
     public static final int CONNECTIVITY_JOB_ID = ConnectivityConstraintTest.class.hashCode();
     /** Wait this long before timing out the test. */
     private static final long DEFAULT_TIMEOUT_MILLIS = 30000L; // 30 seconds.
 
+    private NetworkingHelper mNetworkingHelper;
     private WifiManager mWifiManager;
     private ConnectivityManager mCm;
 
@@ -89,21 +61,8 @@
     private boolean mHasWifi;
     /** Whether the device running these tests supports telephony. */
     private boolean mHasTelephony;
-    /** Whether the device running these tests supports ethernet. */
-    private boolean mHasEthernet;
-    /** Track whether WiFi was enabled in case we turn it off. */
-    private boolean mInitialWiFiState;
-    /** Track initial WiFi metered state. */
-    private String mInitialWiFiMeteredState;
-    private String mInitialWiFiSSID;
-    /** Track whether restrict background policy was enabled in case we turn it off. */
-    private boolean mInitialRestrictBackground;
-    /** Track whether airplane mode was enabled in case we toggle it. */
-    private boolean mInitialAirplaneMode;
     /** Track whether the restricted bucket was enabled in case we toggle it. */
     private String mInitialRestrictedBucketEnabled;
-    /** Track the location mode in case we change it. */
-    private String mInitialLocationMode;
 
     private JobInfo.Builder mBuilder;
 
@@ -115,30 +74,20 @@
 
         mWifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE);
         mCm = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
+        mNetworkingHelper = new NetworkingHelper(getInstrumentation(), getContext());
 
         PackageManager packageManager = mContext.getPackageManager();
         mHasWifi = packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI);
         mHasTelephony = packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
-        mHasEthernet = packageManager.hasSystemFeature(PackageManager.FEATURE_ETHERNET);
         mBuilder = new JobInfo.Builder(CONNECTIVITY_JOB_ID, kJobServiceComponent);
 
-        mInitialLocationMode = Settings.Secure.getString(mContext.getContentResolver(),
-                Settings.Secure.LOCATION_MODE);
         if (mHasWifi) {
-            mInitialWiFiState = mWifiManager.isWifiEnabled();
-            ensureSavedWifiNetwork(mWifiManager);
-            setWifiState(true, mCm, mWifiManager);
-            mInitialWiFiSSID = getWifiSSID();
-            mInitialWiFiMeteredState = getWifiMeteredStatus(mInitialWiFiSSID);
+            mNetworkingHelper.ensureSavedWifiNetwork();
         }
-        mInitialRestrictBackground = SystemUtil
-                .runShellCommand(getInstrumentation(), RESTRICT_BACKGROUND_GET_CMD)
-                .contains("enabled");
         mInitialRestrictedBucketEnabled = Settings.Global.getString(mContext.getContentResolver(),
                 Settings.Global.ENABLE_RESTRICTED_BUCKET);
         setDataSaverEnabled(false);
-        mInitialAirplaneMode = isAirplaneModeOn();
-        setAirplaneMode(false);
+        mNetworkingHelper.setAllNetworksEnabled(true);
         // Force the test app out of the never bucket.
         SystemUtil.runShellCommand("am set-standby-bucket "
                 + TestAppInterface.TEST_APP_PACKAGE + " rare");
@@ -153,31 +102,12 @@
 
         BatteryUtils.runDumpsysBatteryReset();
 
-        // Restore initial restrict background data usage policy
-        setDataSaverEnabled(mInitialRestrictBackground);
-
         // Restore initial restricted bucket setting.
         Settings.Global.putString(mContext.getContentResolver(),
                 Settings.Global.ENABLE_RESTRICTED_BUCKET, mInitialRestrictedBucketEnabled);
 
         // Ensure that we leave WiFi in its previous state.
-        if (mHasWifi) {
-            setWifiMeteredState(mInitialWiFiSSID, mInitialWiFiMeteredState);
-            if (mWifiManager.isWifiEnabled() != mInitialWiFiState) {
-                try {
-                    setWifiState(mInitialWiFiState, mCm, mWifiManager);
-                } catch (AssertionFailedError e) {
-                    // Don't fail the test just because wifi state wasn't set in tearDown.
-                    Log.e(TAG, "Failed to return wifi state to " + mInitialWiFiState, e);
-                }
-            }
-        }
-
-        // Restore initial airplane mode status. Do it after setting wifi in case wifi was
-        // originally metered.
-        setAirplaneMode(mInitialAirplaneMode);
-
-        setLocationMode(mInitialLocationMode);
+        mNetworkingHelper.tearDown();
 
         super.tearDown();
     }
@@ -585,7 +515,7 @@
     }
 
     public void testJobParametersNetwork() throws Exception {
-        setAirplaneMode(false);
+        mNetworkingHelper.setAllNetworksEnabled(true);
 
         // Everything good.
         final NetworkRequest nr = new NetworkRequest.Builder()
@@ -608,7 +538,7 @@
 
         if (!hasEthernetConnection()) {
             // Deadline passed with no network satisfied.
-            setAirplaneMode(true);
+            mNetworkingHelper.setAllNetworksEnabled(false);
             ji = mBuilder
                     .setRequiredNetwork(nr)
                     .setOverrideDeadline(0)
@@ -624,7 +554,7 @@
         }
 
         // No network requested
-        setAirplaneMode(false);
+        mNetworkingHelper.setAllNetworksEnabled(true);
         ji = mBuilder.setRequiredNetwork(null).build();
         kTestEnvironment.setExpectedExecutions(1);
         mJobScheduler.schedule(ji);
@@ -875,149 +805,25 @@
     }
 
     private boolean hasEthernetConnection() {
-        if (!mHasEthernet) return false;
-        Network[] networks = mCm.getAllNetworks();
-        for (Network network : networks) {
-            if (mCm.getNetworkCapabilities(network).hasTransport(TRANSPORT_ETHERNET)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private String unquoteSSID(String ssid) {
-        // SSID is returned surrounded by quotes if it can be decoded as UTF-8.
-        // Otherwise it's guaranteed not to start with a quote.
-        if (ssid.charAt(0) == '"') {
-            return ssid.substring(1, ssid.length() - 1);
-        } else {
-            return ssid;
-        }
-    }
-
-    private String getWifiSSID() throws Exception {
-        // Location needs to be enabled to get the WiFi information.
-        setLocationMode(String.valueOf(Settings.Secure.LOCATION_MODE_ON));
-        final AtomicReference<String> ssid = new AtomicReference<>();
-        SystemUtil.runWithShellPermissionIdentity(() -> {
-            ssid.set(mWifiManager.getConnectionInfo().getSSID());
-        }, Manifest.permission.ACCESS_FINE_LOCATION);
-        return unquoteSSID(ssid.get());
-    }
-
-    private void setLocationMode(String mode) throws Exception {
-        Settings.Secure.putString(mContext.getContentResolver(),
-                Settings.Secure.LOCATION_MODE, mode);
-        final LocationManager locationManager = mContext.getSystemService(LocationManager.class);
-        final boolean wantEnabled = !String.valueOf(Settings.Secure.LOCATION_MODE_OFF).equals(mode);
-        waitUntil("Location " + (wantEnabled ? "not enabled" : "still enabled"),
-                () -> wantEnabled == locationManager.isLocationEnabled());
-    }
-
-    // Returns "true", "false" or "none"
-    private String getWifiMeteredStatus(String ssid) {
-        // Interestingly giving the SSID as an argument to list wifi-networks
-        // only works iff the network in question has the "false" policy.
-        // Also unfortunately runShellCommand does not pass the command to the interpreter
-        // so it's not possible to | grep the ssid.
-        final String command = "cmd netpolicy list wifi-networks";
-        final String policyString = SystemUtil.runShellCommand(command);
-
-        final Matcher m = Pattern.compile("^" + ssid + ";(true|false|none)$",
-                Pattern.MULTILINE | Pattern.UNIX_LINES).matcher(policyString);
-        if (!m.find()) {
-            fail("Unexpected format from cmd netpolicy (when looking for " + ssid + "): "
-                    + policyString);
-        }
-        return m.group(1);
+        return mNetworkingHelper.hasEthernetConnection();
     }
 
     private void setWifiMeteredState(boolean metered) throws Exception {
-        if (metered) {
-            // Make sure unmetered cellular networks don't interfere.
-            setAirplaneMode(true);
-            setWifiState(true, mCm, mWifiManager);
-        }
-        final String ssid = getWifiSSID();
-        setWifiMeteredState(ssid, metered ? "true" : "false");
-    }
-
-    // metered should be "true", "false" or "none"
-    private void setWifiMeteredState(String ssid, String metered) throws Exception {
-        if (metered.equals(getWifiMeteredStatus(ssid))) {
-            return;
-        }
-        SystemUtil.runShellCommand("cmd netpolicy set metered-network " + ssid + " " + metered);
-        assertEquals(getWifiMeteredStatus(ssid), metered);
+        mNetworkingHelper.setWifiMeteredState(metered);
     }
 
     /**
      * Ensure WiFi is enabled, and block until we've verified that we are in fact connected.
      */
     private void connectToWifi() throws Exception {
-        setWifiState(true, mCm, mWifiManager);
+        mNetworkingHelper.setWifiState(true);
     }
 
     /**
      * Ensure WiFi is disabled, and block until we've verified that we are in fact disconnected.
      */
     private void disconnectFromWifi() throws Exception {
-        setWifiState(false, mCm, mWifiManager);
-    }
-
-    /** Ensures that the device has a wifi network saved. */
-    static void ensureSavedWifiNetwork(WifiManager wifiManager) {
-        final List<WifiConfiguration> savedNetworks =
-                ShellIdentityUtils.invokeMethodWithShellPermissions(
-                        wifiManager, WifiManager::getConfiguredNetworks);
-        assertFalse("Need at least one saved wifi network", savedNetworks.isEmpty());
-    }
-
-    /**
-     * Set Wifi connection to specific state, and block until we've verified
-     * that we are in the state.
-     * Taken from {@link android.net.http.cts.ApacheHttpClientTest}.
-     */
-    static void setWifiState(final boolean enable,
-            final ConnectivityManager cm, final WifiManager wm) throws Exception {
-        if (enable != isWiFiConnected(cm, wm)) {
-            NetworkRequest nr = new NetworkRequest.Builder().clearCapabilities().build();
-            NetworkCapabilities nc = new NetworkCapabilities.Builder()
-                    .addTransportType(TRANSPORT_WIFI)
-                    .build();
-            NetworkTracker tracker = new NetworkTracker(nc, enable, cm);
-            cm.registerNetworkCallback(nr, tracker);
-
-            if (enable) {
-                SystemUtil.runShellCommand("svc wifi enable");
-                waitUntil("Failed to enable Wifi", 30 /* seconds */, () -> wm.isWifiEnabled());
-                //noinspection deprecation
-                SystemUtil.runWithShellPermissionIdentity(wm::reconnect,
-                        android.Manifest.permission.NETWORK_SETTINGS);
-            } else {
-                SystemUtil.runShellCommand("svc wifi disable");
-            }
-
-            tracker.waitForStateChange();
-
-            assertTrue("Wifi must be " + (enable ? "connected to" : "disconnected from")
-                            + " an access point for this test.",
-                    enable == isWiFiConnected(cm, wm));
-
-            cm.unregisterNetworkCallback(tracker);
-        }
-    }
-
-    static boolean isWiFiConnected(final ConnectivityManager cm, final WifiManager wm) {
-        if (!wm.isWifiEnabled()) {
-            return false;
-        }
-        final Network network = cm.getActiveNetwork();
-        if (network == null) {
-            return false;
-        }
-        final NetworkCapabilities networkCapabilities = cm.getNetworkCapabilities(network);
-        return networkCapabilities != null && networkCapabilities.hasTransport(TRANSPORT_WIFI);
+        mNetworkingHelper.setWifiState(false);
     }
 
     /**
@@ -1029,13 +835,14 @@
      * @see #checkDeviceSupportsMobileData()
      */
     private void disconnectWifiToConnectToMobile() throws Exception {
-        setAirplaneMode(false);
+        mNetworkingHelper.setAllNetworksEnabled(true);
         if (mHasWifi && mWifiManager.isWifiEnabled()) {
             NetworkRequest nr = new NetworkRequest.Builder().clearCapabilities().build();
             NetworkCapabilities nc = new NetworkCapabilities.Builder()
                     .addTransportType(TRANSPORT_CELLULAR)
                     .build();
-            NetworkTracker tracker = new NetworkTracker(nc, true, mCm);
+            NetworkingHelper.NetworkTracker tracker =
+                    new NetworkingHelper.NetworkTracker(nc, true, mCm);
             mCm.registerNetworkCallback(nr, tracker);
 
             disconnectFromWifi();
@@ -1052,107 +859,6 @@
      * If the policy is on, it interferes with tests that relies on metered connection.
      */
     private void setDataSaverEnabled(boolean enabled) throws Exception {
-        SystemUtil.runShellCommand(getInstrumentation(),
-                enabled ? RESTRICT_BACKGROUND_ON_CMD : RESTRICT_BACKGROUND_OFF_CMD);
-    }
-
-    private boolean isAirplaneModeOn() throws Exception {
-        final String output = SystemUtil.runShellCommand(getInstrumentation(),
-                "cmd connectivity airplane-mode").trim();
-        return "enabled".equals(output);
-    }
-
-    private void setAirplaneMode(boolean on) throws Exception {
-        if (isAirplaneModeOn() == on) {
-            return;
-        }
-        final CallbackAsserter airplaneModeBroadcastAsserter = CallbackAsserter.forBroadcast(
-                new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED));
-        SystemUtil.runShellCommand(getInstrumentation(),
-                "cmd connectivity airplane-mode " + (on ? "enable" : "disable"));
-        airplaneModeBroadcastAsserter.assertCalled("Didn't get airplane mode changed broadcast",
-                15 /* 15 seconds */);
-        waitUntil("Networks didn't change to " + (!on ? " on" : " off"), 60 /* seconds */,
-                () -> {
-                    if (on) {
-                        return mCm.getActiveNetwork() == null
-                                && (!mHasWifi || !isWiFiConnected(mCm, mWifiManager));
-                    } else {
-                        return mCm.getActiveNetwork() != null;
-                    }
-                });
-        // Wait some time for the network changes to propagate. Can't use
-        // waitUntil(isAirplaneModeOn() == on) because the response quickly gives the new
-        // airplane mode status even though the network changes haven't propagated all the way to
-        // JobScheduler.
-        Thread.sleep(5000);
-    }
-
-    private static class NetworkTracker extends ConnectivityManager.NetworkCallback {
-        private static final int MSG_CHECK_ACTIVE_NETWORK = 1;
-        private final ConnectivityManager mCm;
-
-        private final CountDownLatch mReceiveLatch = new CountDownLatch(1);
-
-        private final NetworkCapabilities mExpectedCapabilities;
-
-        private final boolean mExpectedConnected;
-
-        private final Handler mHandler = new Handler(Looper.getMainLooper()) {
-            @Override
-            public void handleMessage(Message msg) {
-                if (msg.what == MSG_CHECK_ACTIVE_NETWORK) {
-                    checkActiveNetwork();
-                }
-            }
-        };
-
-        private NetworkTracker(NetworkCapabilities expectedCapabilities, boolean expectedConnected,
-                ConnectivityManager cm) {
-            mExpectedCapabilities = expectedCapabilities;
-            mExpectedConnected = expectedConnected;
-            mCm = cm;
-        }
-
-        @Override
-        public void onAvailable(Network network) {
-            // Available doesn't mean it's the active network. We need to check that separately.
-            checkActiveNetwork();
-        }
-
-        @Override
-        public void onLost(Network network) {
-            checkActiveNetwork();
-        }
-
-        boolean waitForStateChange() throws InterruptedException {
-            checkActiveNetwork();
-            return mReceiveLatch.await(60, TimeUnit.SECONDS);
-        }
-
-        private void checkActiveNetwork() {
-            mHandler.removeMessages(MSG_CHECK_ACTIVE_NETWORK);
-            if (mReceiveLatch.getCount() == 0) {
-                return;
-            }
-
-            Network activeNetwork = mCm.getActiveNetwork();
-            if (mExpectedConnected) {
-                if (activeNetwork != null && mExpectedCapabilities.satisfiedByNetworkCapabilities(
-                        mCm.getNetworkCapabilities(activeNetwork))) {
-                    mReceiveLatch.countDown();
-                } else {
-                    mHandler.sendEmptyMessageDelayed(MSG_CHECK_ACTIVE_NETWORK, 5000);
-                }
-            } else {
-                if (activeNetwork == null
-                        || !mExpectedCapabilities.satisfiedByNetworkCapabilities(
-                        mCm.getNetworkCapabilities(activeNetwork))) {
-                    mReceiveLatch.countDown();
-                } else {
-                    mHandler.sendEmptyMessageDelayed(MSG_CHECK_ACTIVE_NETWORK, 5000);
-                }
-            }
-        }
+        mNetworkingHelper.setDataSaverEnabled(enabled);
     }
 }
diff --git a/tests/JobScheduler/src/android/jobscheduler/cts/JobThrottlingTest.java b/tests/JobScheduler/src/android/jobscheduler/cts/JobThrottlingTest.java
index b885a57..3f386fa 100644
--- a/tests/JobScheduler/src/android/jobscheduler/cts/JobThrottlingTest.java
+++ b/tests/JobScheduler/src/android/jobscheduler/cts/JobThrottlingTest.java
@@ -18,23 +18,17 @@
 
 import static android.app.job.JobInfo.NETWORK_TYPE_ANY;
 import static android.app.job.JobInfo.NETWORK_TYPE_NONE;
-import static android.jobscheduler.cts.ConnectivityConstraintTest.ensureSavedWifiNetwork;
-import static android.jobscheduler.cts.ConnectivityConstraintTest.isWiFiConnected;
-import static android.jobscheduler.cts.ConnectivityConstraintTest.setWifiState;
 import static android.jobscheduler.cts.TestAppInterface.TEST_APP_PACKAGE;
 import static android.os.PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED;
 
 import static com.android.compatibility.common.util.TestUtils.waitUntil;
 
-import static junit.framework.Assert.fail;
-
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assume.assumeFalse;
 import static org.junit.Assume.assumeTrue;
 
-import android.Manifest;
 import android.app.AppOpsManager;
 import android.app.job.JobInfo;
 import android.app.job.JobParameters;
@@ -44,9 +38,6 @@
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.jobscheduler.cts.jobtestapp.TestJobSchedulerReceiver;
-import android.location.LocationManager;
-import android.net.ConnectivityManager;
-import android.net.wifi.WifiManager;
 import android.os.PowerManager;
 import android.os.SystemClock;
 import android.os.Temperature;
@@ -64,23 +55,14 @@
 import com.android.compatibility.common.util.AppOpsUtils;
 import com.android.compatibility.common.util.AppStandbyUtils;
 import com.android.compatibility.common.util.BatteryUtils;
-import com.android.compatibility.common.util.CallbackAsserter;
 import com.android.compatibility.common.util.DeviceConfigStateHelper;
-import com.android.compatibility.common.util.SystemUtil;
 import com.android.compatibility.common.util.ThermalUtils;
 
-import junit.framework.AssertionFailedError;
-
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.io.IOException;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
 /**
  * Tests related to job throttling -- device idle, app standby and battery saver.
  */
@@ -106,22 +88,15 @@
 
     private Context mContext;
     private UiDevice mUiDevice;
+    private NetworkingHelper mNetworkingHelper;
     private PowerManager mPowerManager;
     private int mTestJobId;
     private int mTestPackageUid;
     private boolean mDeviceInDoze;
     private boolean mDeviceIdleEnabled;
     private boolean mAppStandbyEnabled;
-    private WifiManager mWifiManager;
-    private ConnectivityManager mCm;
-    /** Whether the device running these tests supports WiFi. */
-    private boolean mHasWifi;
-    /** Track whether WiFi was enabled in case we turn it off. */
-    private boolean mInitialWiFiState;
-    private boolean mInitialAirplaneModeState;
     private String mInitialDisplayTimeout;
     private String mInitialRestrictedBucketEnabled;
-    private String mInitialLocationMode;
     private String mInitialBatteryStatsConstants;
     private boolean mAutomotiveDevice;
     private boolean mLeanbackOnly;
@@ -154,6 +129,8 @@
     public void setUp() throws Exception {
         mContext = InstrumentationRegistry.getTargetContext();
         mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+        mNetworkingHelper =
+                new NetworkingHelper(InstrumentationRegistry.getInstrumentation(), mContext);
         mPowerManager = mContext.getSystemService(PowerManager.class);
         mDeviceInDoze = mPowerManager.isDeviceIdleMode();
         mTestPackageUid = mContext.getPackageManager().getPackageUid(TEST_APP_PACKAGE, 0);
@@ -171,11 +148,6 @@
         } else {
             Log.w(TAG, "App standby not enabled on test device");
         }
-        mWifiManager = mContext.getSystemService(WifiManager.class);
-        mCm = mContext.getSystemService(ConnectivityManager.class);
-        mHasWifi = mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI);
-        mInitialWiFiState = mWifiManager.isWifiEnabled();
-        mInitialAirplaneModeState = isAirplaneModeOn();
         mInitialRestrictedBucketEnabled = Settings.Global.getString(mContext.getContentResolver(),
                 Settings.Global.ENABLE_RESTRICTED_BUCKET);
         mInitialBatteryStatsConstants = Settings.Global.getString(mContext.getContentResolver(),
@@ -183,8 +155,6 @@
         // Make sure ACTION_CHARGING is sent immediately.
         Settings.Global.putString(mContext.getContentResolver(),
                 Settings.Global.BATTERY_STATS_CONSTANTS, "battery_charged_delay_ms=0");
-        mInitialLocationMode = Settings.Secure.getString(mContext.getContentResolver(),
-                Settings.Secure.LOCATION_MODE);
         // Make sure test jobs can run regardless of bucket.
         mDeviceConfigStateHelper =
                 new DeviceConfigStateHelper(DeviceConfig.NAMESPACE_JOB_SCHEDULER);
@@ -603,7 +573,7 @@
         mDeviceConfigStateHelper.set("qc_timing_session_coalescing_duration_ms", "0");
         mDeviceConfigStateHelper.set("qc_max_session_count_restricted", "0");
 
-        setAirplaneMode(true);
+        mNetworkingHelper.setAllNetworksEnabled(false);
         setScreenState(true);
 
         setChargingState(false);
@@ -634,9 +604,9 @@
         assumeTrue("app standby not enabled", mAppStandbyEnabled);
         assumeFalse("not testable in automotive device", mAutomotiveDevice);
         assumeFalse("not testable in leanback device", mLeanbackOnly);
-
-        assumeTrue(mHasWifi);
-        ensureSavedWifiNetwork(mWifiManager);
+        assumeFalse("not testable, since ethernet is connected", hasEthernetConnection());
+        assumeTrue(mNetworkingHelper.hasWifiFeature());
+        mNetworkingHelper.ensureSavedWifiNetwork();
 
         setRestrictedBucketEnabled(true);
 
@@ -644,7 +614,7 @@
         mDeviceConfigStateHelper.set("qc_timing_session_coalescing_duration_ms", "0");
         mDeviceConfigStateHelper.set("qc_max_session_count_restricted", "0");
 
-        setAirplaneMode(true);
+        mNetworkingHelper.setAllNetworksEnabled(false);
         setScreenState(true);
 
         setChargingState(false);
@@ -673,9 +643,8 @@
         assertFalse("New job started in RESTRICTED bucket", mTestAppInterface.awaitJobStart(3_000));
 
         // Add network
-        setAirplaneMode(false);
-        setWifiState(true, mCm, mWifiManager);
-        setWifiMeteredState(false);
+        mNetworkingHelper.setAllNetworksEnabled(true);
+        mNetworkingHelper.setWifiMeteredState(false);
         runJob();
         assertTrue("New job didn't start in RESTRICTED bucket",
                 mTestAppInterface.awaitJobStart(5_000));
@@ -978,8 +947,8 @@
         assumeFalse("not testable in automotive device", mAutomotiveDevice);
         assumeFalse("not testable in leanback device", mLeanbackOnly);
 
-        assumeTrue(mHasWifi);
-        ensureSavedWifiNetwork(mWifiManager);
+        assumeTrue(mNetworkingHelper.hasWifiFeature());
+        mNetworkingHelper.ensureSavedWifiNetwork();
 
         setRestrictedBucketEnabled(true);
         setTestPackageStandbyBucket(Bucket.RESTRICTED);
@@ -989,9 +958,8 @@
         mDeviceConfigStateHelper.set("qc_max_session_count_restricted", "0");
 
         // Satisfy all additional constraints.
-        setAirplaneMode(false);
-        setWifiState(true, mCm, mWifiManager);
-        setWifiMeteredState(false);
+        mNetworkingHelper.setAllNetworksEnabled(true);
+        mNetworkingHelper.setWifiMeteredState(false);
         setChargingState(true);
         BatteryUtils.runDumpsysBatterySetLevel(100);
         setScreenState(false);
@@ -1004,13 +972,12 @@
         runJob();
         assertTrue("New job didn't start in RESTRICTED bucket",
                 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT));
-        setAirplaneMode(true);
+        mNetworkingHelper.setAllNetworksEnabled(false);
         assertTrue("New job didn't stop when connectivity dropped",
                 mTestAppInterface.awaitJobStop(DEFAULT_WAIT_TIMEOUT));
         assertEquals(JobParameters.STOP_REASON_CONSTRAINT_CONNECTIVITY,
                 mTestAppInterface.getLastParams().getStopReason());
-        setAirplaneMode(false);
-        setWifiState(true, mCm, mWifiManager);
+        mNetworkingHelper.setAllNetworksEnabled(true);
 
         // Idle
         mTestAppInterface.scheduleJob(false, NETWORK_TYPE_ANY, false);
@@ -1195,23 +1162,12 @@
                 Settings.Global.BATTERY_STATS_CONSTANTS, mInitialBatteryStatsConstants);
         removeTestAppFromTempWhitelist();
 
-        // Ensure that we leave WiFi in its previous state.
-        if (mHasWifi && mWifiManager.isWifiEnabled() != mInitialWiFiState) {
-            try {
-                setWifiState(mInitialWiFiState, mCm, mWifiManager);
-            } catch (AssertionFailedError e) {
-                // Don't fail the test just because wifi state wasn't set in tearDown.
-                Log.e(TAG, "Failed to return wifi state to " + mInitialWiFiState, e);
-            }
-        }
+        mNetworkingHelper.tearDown();
         mDeviceConfigStateHelper.restoreOriginalValues();
         mActivityManagerDeviceConfigStateHelper.restoreOriginalValues();
         Settings.Global.putString(mContext.getContentResolver(),
                 Settings.Global.ENABLE_RESTRICTED_BUCKET, mInitialRestrictedBucketEnabled);
-        if (isAirplaneModeOn() != mInitialAirplaneModeState) {
-            setAirplaneMode(mInitialAirplaneModeState);
-        }
-        setLocationMode(mInitialLocationMode);
+
         mUiDevice.executeShellCommand(
                 "cmd jobscheduler reset-execution-quota -u " + UserHandle.myUserId()
                         + " " + TEST_APP_PACKAGE);
@@ -1367,110 +1323,8 @@
                 + " -u " + UserHandle.myUserId() + " " + TEST_APP_PACKAGE + " " + mTestJobId);
     }
 
-    private boolean isAirplaneModeOn() throws IOException {
-        final String output =
-                mUiDevice.executeShellCommand("cmd connectivity airplane-mode").trim();
-        return "enabled".equals(output);
-    }
-
-    private void setAirplaneMode(boolean on) throws Exception {
-        final CallbackAsserter airplaneModeBroadcastAsserter = CallbackAsserter.forBroadcast(
-                new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED));
-        mUiDevice.executeShellCommand(
-                "cmd connectivity airplane-mode " + (on ? "enable" : "disable"));
-        airplaneModeBroadcastAsserter.assertCalled("Didn't get airplane mode changed broadcast",
-                15 /* 15 seconds */);
-        if (!on && mHasWifi) {
-            // Force wifi to connect ASAP.
-            mUiDevice.executeShellCommand("svc wifi enable");
-            waitUntil("Failed to enable Wifi", 30 /* seconds */,
-                    () -> {
-                        return mWifiManager.isWifiEnabled();
-                    });
-            //noinspection deprecation
-            SystemUtil.runWithShellPermissionIdentity(mWifiManager::reconnect,
-                    android.Manifest.permission.NETWORK_SETTINGS);
-        }
-        waitUntil("Networks didn't change to " + (!on ? "on" : "off"), 60 /* seconds */,
-                () -> {
-                    if (on) {
-                        return mCm.getActiveNetwork() == null
-                                && (!mHasWifi || !isWiFiConnected(mCm, mWifiManager));
-                    } else {
-                        return mCm.getActiveNetwork() != null;
-                    }
-                });
-        // Wait some time for the network changes to propagate. Can't use
-        // waitUntil(isAirplaneModeOn() == on) because the response quickly gives the new
-        // airplane mode status even though the network changes haven't propagated all the way to
-        // JobScheduler.
-        Thread.sleep(5000);
-    }
-
-    private static String unquoteSSID(String ssid) {
-        // SSID is returned surrounded by quotes if it can be decoded as UTF-8.
-        // Otherwise it's guaranteed not to start with a quote.
-        if (ssid.charAt(0) == '"') {
-            return ssid.substring(1, ssid.length() - 1);
-        } else {
-            return ssid;
-        }
-    }
-
-    private String getWifiSSID() throws Exception {
-        // Location needs to be enabled to get the WiFi information.
-        setLocationMode(String.valueOf(Settings.Secure.LOCATION_MODE_ON));
-        final AtomicReference<String> ssid = new AtomicReference<>();
-        SystemUtil.runWithShellPermissionIdentity(() -> {
-            ssid.set(mWifiManager.getConnectionInfo().getSSID());
-        }, Manifest.permission.ACCESS_FINE_LOCATION);
-        return unquoteSSID(ssid.get());
-    }
-
-    private void setLocationMode(String mode) throws Exception {
-        Settings.Secure.putString(mContext.getContentResolver(),
-                Settings.Secure.LOCATION_MODE, mode);
-        final LocationManager locationManager = mContext.getSystemService(LocationManager.class);
-        final boolean wantEnabled = !String.valueOf(Settings.Secure.LOCATION_MODE_OFF).equals(mode);
-        waitUntil("Location " + (wantEnabled ? "not enabled" : "still enabled"),
-                () -> wantEnabled == locationManager.isLocationEnabled());
-    }
-
-    // Returns "true", "false" or "none"
-    private String getWifiMeteredStatus(String ssid) {
-        // Interestingly giving the SSID as an argument to list wifi-networks
-        // only works iff the network in question has the "false" policy.
-        // Also unfortunately runShellCommand does not pass the command to the interpreter
-        // so it's not possible to | grep the ssid.
-        final String command = "cmd netpolicy list wifi-networks";
-        final String policyString = SystemUtil.runShellCommand(command);
-
-        final Matcher m = Pattern.compile("^" + ssid + ";(true|false|none)$",
-                Pattern.MULTILINE | Pattern.UNIX_LINES).matcher(policyString);
-        if (!m.find()) {
-            fail("Unexpected format from cmd netpolicy (when looking for " + ssid + "): "
-                    + policyString);
-        }
-        return m.group(1);
-    }
-
-    private void setWifiMeteredState(boolean metered) throws Exception {
-        if (metered) {
-            // Make sure unmetered cellular networks don't interfere.
-            setAirplaneMode(true);
-            setWifiState(true, mCm, mWifiManager);
-        }
-        final String ssid = getWifiSSID();
-        setWifiMeteredState(ssid, metered ? "true" : "false");
-    }
-
-    // metered should be "true", "false" or "none"
-    private void setWifiMeteredState(String ssid, String metered) {
-        if (metered.equals(getWifiMeteredStatus(ssid))) {
-            return;
-        }
-        SystemUtil.runShellCommand("cmd netpolicy set metered-network " + ssid + " " + metered);
-        assertEquals(getWifiMeteredStatus(ssid), metered);
+    private boolean hasEthernetConnection() {
+        return mNetworkingHelper.hasEthernetConnection();
     }
 
     private String getJobState() throws Exception {
diff --git a/tests/JobScheduler/src/android/jobscheduler/cts/NetworkingHelper.java b/tests/JobScheduler/src/android/jobscheduler/cts/NetworkingHelper.java
new file mode 100644
index 0000000..1402975
--- /dev/null
+++ b/tests/JobScheduler/src/android/jobscheduler/cts/NetworkingHelper.java
@@ -0,0 +1,432 @@
+/*
+ * Copyright (C) 2022 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 android.jobscheduler.cts;
+
+import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+
+import static com.android.compatibility.common.util.TestUtils.waitUntil;
+
+import static junit.framework.Assert.fail;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import android.Manifest;
+import android.annotation.NonNull;
+import android.app.Instrumentation;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.location.LocationManager;
+import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkRequest;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiManager;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.provider.Settings;
+import android.util.Log;
+
+import com.android.compatibility.common.util.CallbackAsserter;
+import com.android.compatibility.common.util.ShellIdentityUtils;
+import com.android.compatibility.common.util.SystemUtil;
+
+import junit.framework.AssertionFailedError;
+
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class NetworkingHelper {
+    private static final String TAG = "JsNetworkingUtils";
+
+    private static final String RESTRICT_BACKGROUND_GET_CMD =
+            "cmd netpolicy get restrict-background";
+    private static final String RESTRICT_BACKGROUND_ON_CMD =
+            "cmd netpolicy set restrict-background true";
+    private static final String RESTRICT_BACKGROUND_OFF_CMD =
+            "cmd netpolicy set restrict-background false";
+
+    private final Context mContext;
+    private final Instrumentation mInstrumentation;
+
+    private final ConnectivityManager mConnectivityManager;
+    private final WifiManager mWifiManager;
+
+    /** Whether the device running these tests supports WiFi. */
+    private final boolean mHasWifi;
+    /** Whether the device running these tests supports ethernet. */
+    private final boolean mHasEthernet;
+    /** Whether the device running these tests supports telephony. */
+    private final boolean mHasTelephony;
+
+    private final boolean mInitialAirplaneModeState;
+    private final boolean mInitialDataSaverState;
+    private final String mInitialLocationMode;
+    private final boolean mInitialWiFiState;
+    private String mInitialWiFiMeteredState;
+    private String mInitialWiFiSSID;
+
+    NetworkingHelper(@NonNull Instrumentation instrumentation, @NonNull Context context)
+            throws Exception {
+        mContext = context;
+        mInstrumentation = instrumentation;
+
+        mConnectivityManager = context.getSystemService(ConnectivityManager.class);
+        mWifiManager = context.getSystemService(WifiManager.class);
+
+        PackageManager packageManager = mContext.getPackageManager();
+        mHasWifi = packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI);
+        mHasEthernet = packageManager.hasSystemFeature(PackageManager.FEATURE_ETHERNET);
+        mHasTelephony = packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
+
+        mInitialAirplaneModeState = isAirplaneModeOn();
+        mInitialDataSaverState = isDataSaverEnabled();
+        mInitialLocationMode = Settings.Secure.getString(
+                mContext.getContentResolver(), Settings.Secure.LOCATION_MODE);
+        mInitialWiFiState = mHasWifi && isWifiEnabled();
+    }
+
+    /** Ensures that the device has a wifi network saved. */
+    void ensureSavedWifiNetwork() throws Exception {
+        if (!mHasWifi) {
+            return;
+        }
+        final List<WifiConfiguration> savedNetworks =
+                ShellIdentityUtils.invokeMethodWithShellPermissions(
+                        mWifiManager, WifiManager::getConfiguredNetworks);
+        assertFalse("Need at least one saved wifi network", savedNetworks.isEmpty());
+
+        setWifiState(true);
+        if (mInitialWiFiSSID == null) {
+            mInitialWiFiSSID = getWifiSSID();
+            mInitialWiFiMeteredState = getWifiMeteredStatus(mInitialWiFiSSID);
+        }
+    }
+
+    // Returns "true", "false", or "none".
+    private String getWifiMeteredStatus(String ssid) {
+        // Interestingly giving the SSID as an argument to list wifi-networks
+        // only works iff the network in question has the "false" policy.
+        // Also unfortunately runShellCommand does not pass the command to the interpreter
+        // so it's not possible to | grep the ssid.
+        final String command = "cmd netpolicy list wifi-networks";
+        final String policyString = SystemUtil.runShellCommand(command);
+
+        final Matcher m = Pattern.compile(ssid + ";(true|false|none)",
+                Pattern.MULTILINE | Pattern.UNIX_LINES).matcher(policyString);
+        if (!m.find()) {
+            fail("Unexpected format from cmd netpolicy (when looking for " + ssid + "): "
+                    + policyString);
+        }
+        return m.group(1);
+    }
+
+    @NonNull
+    private String getWifiSSID() throws Exception {
+        // Location needs to be enabled to get the WiFi information.
+        setLocationMode(String.valueOf(Settings.Secure.LOCATION_MODE_ON));
+        final AtomicReference<String> ssid = new AtomicReference<>();
+        SystemUtil.runWithShellPermissionIdentity(
+                () -> ssid.set(mWifiManager.getConnectionInfo().getSSID()),
+                Manifest.permission.ACCESS_FINE_LOCATION);
+        return unquoteSSID(ssid.get());
+    }
+
+    boolean hasEthernetConnection() {
+        if (!mHasEthernet) return false;
+        Network[] networks = mConnectivityManager.getAllNetworks();
+        for (Network network : networks) {
+            if (mConnectivityManager.getNetworkCapabilities(network)
+                    .hasTransport(TRANSPORT_ETHERNET)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    boolean hasWifiFeature() {
+        return mHasWifi;
+    }
+
+    boolean isAirplaneModeOn() throws Exception {
+        final String output = SystemUtil.runShellCommand(mInstrumentation,
+                "cmd connectivity airplane-mode").trim();
+        return "enabled".equals(output);
+    }
+
+    boolean isDataSaverEnabled() throws Exception {
+        return SystemUtil
+                .runShellCommand(mInstrumentation, RESTRICT_BACKGROUND_GET_CMD)
+                .contains("enabled");
+    }
+
+    boolean isWiFiConnected() {
+        if (!mWifiManager.isWifiEnabled()) {
+            return false;
+        }
+        final Network network = mConnectivityManager.getActiveNetwork();
+        if (network == null) {
+            return false;
+        }
+        final NetworkCapabilities networkCapabilities =
+                mConnectivityManager.getNetworkCapabilities(network);
+        return networkCapabilities != null && networkCapabilities.hasTransport(TRANSPORT_WIFI);
+    }
+
+    boolean isWifiEnabled() {
+        return mWifiManager.isWifiEnabled();
+    }
+
+    /**
+     * Tries to set all network statuses to {@code enabled}.
+     * However, this does not support ethernet connections.
+     * Confirm that {@link #hasEthernetConnection()} returns false before relying on this.
+     */
+    void setAllNetworksEnabled(boolean enabled) throws Exception {
+        if (mHasWifi) {
+            setWifiState(enabled);
+        }
+        setAirplaneMode(!enabled);
+    }
+
+    void setAirplaneMode(boolean on) throws Exception {
+        if (isAirplaneModeOn() == on) {
+            return;
+        }
+        final CallbackAsserter airplaneModeBroadcastAsserter = CallbackAsserter.forBroadcast(
+                new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED));
+        SystemUtil.runShellCommand(mInstrumentation,
+                "cmd connectivity airplane-mode " + (on ? "enable" : "disable"));
+        airplaneModeBroadcastAsserter.assertCalled("Didn't get airplane mode changed broadcast",
+                15 /* 15 seconds */);
+        if (!on && mHasWifi) {
+            // Try to trigger some network connection.
+            setWifiState(true);
+        }
+        waitUntil("Airplane mode didn't change to " + (on ? " on" : " off"), 60 /* seconds */,
+                () -> {
+                    // Airplane mode only affects the cellular network. If the device doesn't
+                    // support cellular, then we can only check that the airplane mode toggle is on.
+                    if (!mHasTelephony) {
+                        return on == isAirplaneModeOn();
+                    }
+                    if (on) {
+                        Network[] networks = mConnectivityManager.getAllNetworks();
+                        for (Network network : networks) {
+                            if (mConnectivityManager.getNetworkCapabilities(network)
+                                    .hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
+                                return false;
+                            }
+                        }
+                        return true;
+                    } else {
+                        return mConnectivityManager.getActiveNetwork() != null;
+                    }
+                });
+        // Wait some time for the network changes to propagate. Can't use
+        // waitUntil(isAirplaneModeOn() == on) because the response quickly gives the new
+        // airplane mode status even though the network changes haven't propagated all the way to
+        // JobScheduler.
+        Thread.sleep(5000);
+    }
+
+    /**
+     * Ensures that restrict background data usage policy is turned off.
+     * If the policy is on, it interferes with tests that relies on metered connection.
+     */
+    void setDataSaverEnabled(boolean enabled) throws Exception {
+        SystemUtil.runShellCommand(mInstrumentation,
+                enabled ? RESTRICT_BACKGROUND_ON_CMD : RESTRICT_BACKGROUND_OFF_CMD);
+    }
+
+    private void setLocationMode(String mode) throws Exception {
+        Settings.Secure.putString(mContext.getContentResolver(),
+                Settings.Secure.LOCATION_MODE, mode);
+        final LocationManager locationManager = mContext.getSystemService(LocationManager.class);
+        final boolean wantEnabled = !String.valueOf(Settings.Secure.LOCATION_MODE_OFF).equals(mode);
+        waitUntil("Location " + (wantEnabled ? "not enabled" : "still enabled"),
+                () -> wantEnabled == locationManager.isLocationEnabled());
+    }
+
+    void setWifiMeteredState(boolean metered) throws Exception {
+        if (metered) {
+            // Make sure unmetered cellular networks don't interfere.
+            setAirplaneMode(true);
+            setWifiState(true);
+        }
+        final String ssid = getWifiSSID();
+        setWifiMeteredState(ssid, metered ? "true" : "false");
+    }
+
+    // metered should be "true", "false" or "none"
+    private void setWifiMeteredState(String ssid, String metered) {
+        if (metered.equals(getWifiMeteredStatus(ssid))) {
+            return;
+        }
+        SystemUtil.runShellCommand("cmd netpolicy set metered-network " + ssid + " " + metered);
+        assertEquals(getWifiMeteredStatus(ssid), metered);
+    }
+
+    /**
+     * Set Wifi connection to specific state, and block until we've verified
+     * that we are in the state.
+     * Taken from {@link android.net.http.cts.ApacheHttpClientTest}.
+     */
+    void setWifiState(final boolean enable) throws Exception {
+        if (enable != isWiFiConnected()) {
+            NetworkRequest nr = new NetworkRequest.Builder().clearCapabilities().build();
+            NetworkCapabilities nc = new NetworkCapabilities.Builder()
+                    .addTransportType(TRANSPORT_WIFI)
+                    .build();
+            NetworkTracker tracker = new NetworkTracker(nc, enable, mConnectivityManager);
+            mConnectivityManager.registerNetworkCallback(nr, tracker);
+
+            if (enable) {
+                SystemUtil.runShellCommand("svc wifi enable");
+                waitUntil("Failed to enable Wifi", 30 /* seconds */,
+                        this::isWifiEnabled);
+                //noinspection deprecation
+                SystemUtil.runWithShellPermissionIdentity(mWifiManager::reconnect,
+                        android.Manifest.permission.NETWORK_SETTINGS);
+            } else {
+                SystemUtil.runShellCommand("svc wifi disable");
+            }
+
+            tracker.waitForStateChange();
+
+            assertEquals("Wifi must be " + (enable ? "connected to" : "disconnected from")
+                    + " an access point for this test.", enable, isWiFiConnected());
+
+            mConnectivityManager.unregisterNetworkCallback(tracker);
+        }
+    }
+
+    void tearDown() throws Exception {
+        // Restore initial restrict background data usage policy
+        setDataSaverEnabled(mInitialDataSaverState);
+
+        // Ensure that we leave WiFi in its previous state.
+        if (mHasWifi) {
+            if (mInitialWiFiSSID != null) {
+                setWifiMeteredState(mInitialWiFiSSID, mInitialWiFiMeteredState);
+            }
+            if (mWifiManager.isWifiEnabled() != mInitialWiFiState) {
+                try {
+                    setWifiState(mInitialWiFiState);
+                } catch (AssertionFailedError e) {
+                    // Don't fail the test just because wifi state wasn't set in tearDown.
+                    Log.e(TAG, "Failed to return wifi state to " + mInitialWiFiState, e);
+                }
+            }
+        }
+
+        // Restore initial airplane mode status. Do it after setting wifi in case wifi was
+        // originally metered.
+        if (isAirplaneModeOn() != mInitialAirplaneModeState) {
+            setAirplaneMode(mInitialAirplaneModeState);
+        }
+
+        setLocationMode(mInitialLocationMode);
+    }
+
+    private String unquoteSSID(String ssid) {
+        // SSID is returned surrounded by quotes if it can be decoded as UTF-8.
+        // Otherwise it's guaranteed not to start with a quote.
+        if (ssid.charAt(0) == '"') {
+            return ssid.substring(1, ssid.length() - 1);
+        } else {
+            return ssid;
+        }
+    }
+
+    static class NetworkTracker extends ConnectivityManager.NetworkCallback {
+        private static final int MSG_CHECK_ACTIVE_NETWORK = 1;
+        private final ConnectivityManager mConnectivityManager;
+
+        private final CountDownLatch mReceiveLatch = new CountDownLatch(1);
+
+        private final NetworkCapabilities mExpectedCapabilities;
+
+        private final boolean mExpectedConnected;
+
+        private final Handler mHandler = new Handler(Looper.getMainLooper()) {
+            @Override
+            public void handleMessage(Message msg) {
+                if (msg.what == MSG_CHECK_ACTIVE_NETWORK) {
+                    checkActiveNetwork();
+                }
+            }
+        };
+
+        NetworkTracker(NetworkCapabilities expectedCapabilities, boolean expectedConnected,
+                ConnectivityManager cm) {
+            mExpectedCapabilities = expectedCapabilities;
+            mExpectedConnected = expectedConnected;
+            mConnectivityManager = cm;
+        }
+
+        @Override
+        public void onAvailable(Network network) {
+            // Available doesn't mean it's the active network. We need to check that separately.
+            checkActiveNetwork();
+        }
+
+        @Override
+        public void onLost(Network network) {
+            checkActiveNetwork();
+        }
+
+        boolean waitForStateChange() throws InterruptedException {
+            checkActiveNetwork();
+            return mReceiveLatch.await(60, TimeUnit.SECONDS);
+        }
+
+        private void checkActiveNetwork() {
+            mHandler.removeMessages(MSG_CHECK_ACTIVE_NETWORK);
+            if (mReceiveLatch.getCount() == 0) {
+                return;
+            }
+
+            Network activeNetwork = mConnectivityManager.getActiveNetwork();
+            if (mExpectedConnected) {
+                if (activeNetwork != null && mExpectedCapabilities.satisfiedByNetworkCapabilities(
+                        mConnectivityManager.getNetworkCapabilities(activeNetwork))) {
+                    mReceiveLatch.countDown();
+                } else {
+                    mHandler.sendEmptyMessageDelayed(MSG_CHECK_ACTIVE_NETWORK, 5000);
+                }
+            } else {
+                if (activeNetwork == null
+                        || !mExpectedCapabilities.satisfiedByNetworkCapabilities(
+                        mConnectivityManager.getNetworkCapabilities(activeNetwork))) {
+                    mReceiveLatch.countDown();
+                } else {
+                    mHandler.sendEmptyMessageDelayed(MSG_CHECK_ACTIVE_NETWORK, 5000);
+                }
+            }
+        }
+    }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/VisualVoicemailServiceTest.java b/tests/tests/telephony/current/src/android/telephony/cts/VisualVoicemailServiceTest.java
index f77b879..f969182 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/VisualVoicemailServiceTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/VisualVoicemailServiceTest.java
@@ -532,7 +532,8 @@
             for (SmsMessage message : messages) {
                 String body = message.getMessageBody();
 
-                if ((body == null || message.getReceivedEncodingType() == ENCODING_8BIT)
+                if ((body == null || (message.is3gpp()
+                        && message.getReceivedEncodingType() == ENCODING_8BIT))
                         && message.getUserData() != null) {
                     Log.d(TAG, "onReceive decode using UTF-8");
                     // Attempt to interpret the user data as UTF-8. UTF-8 string over data SMS using