Update CTS for unsupported legacy ConnectivityManager APIs

http://ag/736511 made the deprecated ConnectivityManager routing
APIs {start,stop}UsingNetworkFeature and requestRouteToHost throw
exceptions for apps whose target SDK version is 23 or above. Move
the tests for these APIs to a new APK that targets SDK version 22
and update the current test APK to ensure that they throw an
exception.

Bug: 22977863
Bug: 23003441
Bug: 23003635
Change-Id: Icf58e928fdc0018d977ce8aa315866659d32debb
diff --git a/CtsTestCaseList.mk b/CtsTestCaseList.mk
index beb9895..0950994 100644
--- a/CtsTestCaseList.mk
+++ b/CtsTestCaseList.mk
@@ -172,6 +172,7 @@
     CtsNativeOpenGLTestCases \
     CtsNdefTestCases \
     CtsNetTestCases \
+    CtsNetTestCasesLegacyApi22 \
     CtsOpenGLTestCases \
     CtsOpenGlPerfTestCases \
     CtsOsTestCases \
diff --git a/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java
index e4d77b1..88dbd7c 100644
--- a/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -67,7 +67,6 @@
     private PackageManager mPackageManager;
     private final HashMap<Integer, NetworkConfig> mNetworks =
             new HashMap<Integer, NetworkConfig>();
-    private final List<Integer>mProtectedNetworks = new ArrayList<Integer>();
 
     @Override
     protected void setUp() throws Exception {
@@ -90,13 +89,6 @@
                 mNetworks.put(n.type, n);
             } catch (Exception e) {}
         }
-
-        // Get com.android.internal.R.array.config_protectedNetworks
-        resId = getContext().getResources().getIdentifier("config_protectedNetworks", "array", "android");
-        int[] protectedNetworks = getContext().getResources().getIntArray(resId);
-        for (int p : protectedNetworks) {
-            mProtectedNetworks.add(p);
-        }
     }
 
     public void testIsNetworkTypeValid() {
@@ -190,6 +182,27 @@
         }
     }
 
+    private void assertStartUsingNetworkFeatureUnsupported(int networkType, String feature) {
+        try {
+            mCm.startUsingNetworkFeature(networkType, feature);
+            fail("startUsingNetworkFeature is no longer supported in the current API version");
+        } catch (UnsupportedOperationException expected) {}
+    }
+
+    private void assertStopUsingNetworkFeatureUnsupported(int networkType, String feature) {
+        try {
+            mCm.startUsingNetworkFeature(networkType, feature);
+            fail("stopUsingNetworkFeature is no longer supported in the current API version");
+        } catch (UnsupportedOperationException expected) {}
+    }
+
+    private void assertRequestRouteToHostUnsupported(int networkType, int hostAddress) {
+        try {
+            mCm.requestRouteToHost(networkType, hostAddress);
+            fail("requestRouteToHost is no longer supported in the current API version");
+        } catch (UnsupportedOperationException expected) {}
+    }
+
     public void testStartUsingNetworkFeature() {
 
         final String invalidateFeature = "invalidateFeature";
@@ -198,27 +211,9 @@
         final int wifiOnlyStartFailureCode = PhoneConstants.APN_REQUEST_FAILED;
         final int wifiOnlyStopFailureCode = -1;
 
-        NetworkInfo ni = mCm.getNetworkInfo(TYPE_MOBILE);
-        if (ni != null) {
-            assertEquals(PhoneConstants.APN_REQUEST_FAILED,
-                    mCm.startUsingNetworkFeature(TYPE_MOBILE, invalidateFeature));
-            assertEquals(failureCode, mCm.stopUsingNetworkFeature(TYPE_MOBILE,
-                    invalidateFeature));
-        } else {
-            assertEquals(wifiOnlyStartFailureCode, mCm.startUsingNetworkFeature(TYPE_MOBILE,
-                    invalidateFeature));
-            assertEquals(wifiOnlyStopFailureCode, mCm.stopUsingNetworkFeature(TYPE_MOBILE,
-                    invalidateFeature));
-        }
-
-        ni = mCm.getNetworkInfo(TYPE_WIFI);
-        if (ni != null) {
-            // Should return failure because MMS is not supported on WIFI.
-            assertEquals(PhoneConstants.APN_REQUEST_FAILED, mCm.startUsingNetworkFeature(TYPE_WIFI,
-                    mmsFeature));
-            assertEquals(failureCode, mCm.stopUsingNetworkFeature(TYPE_WIFI,
-                    mmsFeature));
-        }
+        assertStartUsingNetworkFeatureUnsupported(TYPE_MOBILE, invalidateFeature);
+        assertStopUsingNetworkFeatureUnsupported(TYPE_MOBILE, invalidateFeature);
+        assertStartUsingNetworkFeatureUnsupported(TYPE_WIFI, mmsFeature);
     }
 
     private boolean isSupported(int networkType) {
@@ -229,11 +224,6 @@
                (networkType == ConnectivityManager.TYPE_VPN);
     }
 
-    // true if only the system can turn it on
-    private boolean isNetworkProtected(int networkType) {
-        return mProtectedNetworks.contains(networkType);
-    }
-
     public void testIsNetworkSupported() {
         for (int type = -1; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) {
             boolean supported = mCm.isNetworkSupported(type);
@@ -247,82 +237,14 @@
 
     public void testRequestRouteToHost() {
         for (int type = -1 ; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) {
-            NetworkInfo ni = mCm.getNetworkInfo(type);
-            boolean expectToWork = isSupported(type) && !isNetworkProtected(type) &&
-                    ni != null && ni.isConnected();
-
-            try {
-                assertTrue("Network type " + type,
-                        mCm.requestRouteToHost(type, HOST_ADDRESS) == expectToWork);
-            } catch (Exception e) {
-                Log.d(TAG, "got exception in requestRouteToHost for type " + type);
-                assertFalse("Exception received for type " + type, expectToWork);
-            }
-
-            //TODO verify route table
+            assertRequestRouteToHostUnsupported(type, HOST_ADDRESS);
         }
-
-        assertFalse(mCm.requestRouteToHost(-1, HOST_ADDRESS));
     }
 
     public void testTest() {
         mCm.getBackgroundDataSetting();
     }
 
-    /** Test that hipri can be brought up when Wifi is enabled. */
-    public void testStartUsingNetworkFeature_enableHipri() throws Exception {
-        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)
-                || !mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)) {
-            // This test requires a mobile data connection and WiFi.
-            return;
-        }
-
-        boolean isWifiEnabled = mWifiManager.isWifiEnabled();
-        boolean isWifiConnected = false;
-
-        NetworkInfo nwInfo = mCm.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
-        if (nwInfo != null) {
-            isWifiConnected = nwInfo.isConnected();
-        }
-        try {
-            // Make sure WiFi is connected to an access point.
-            if (!isWifiConnected) {
-                connectToWifi();
-            }
-
-            // Register a receiver that will capture the connectivity change for hipri.
-            ConnectivityActionReceiver receiver = new ConnectivityActionReceiver(
-                    ConnectivityManager.TYPE_MOBILE_HIPRI, NetworkInfo.State.CONNECTED);
-            IntentFilter filter = new IntentFilter();
-            filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
-            mContext.registerReceiver(receiver, filter);
-
-            // Try to start using the hipri feature...
-            int result = mCm.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
-                    FEATURE_ENABLE_HIPRI);
-            assertTrue("Couldn't start using the HIPRI feature.", result != -1);
-
-            // Check that the ConnectivityManager reported that it connected using hipri...
-            assertTrue("Couldn't connect using hipri...", receiver.waitForState());
-
-            assertTrue("Couldn't requestRouteToHost using HIPRI.",
-                    mCm.requestRouteToHost(ConnectivityManager.TYPE_MOBILE_HIPRI, HOST_ADDRESS));
-            // TODO check dns selection
-            // TODO check routes
-        } catch (InterruptedException e) {
-            fail("Broadcast receiver waiting for ConnectivityManager interrupted.");
-        } finally {
-            mCm.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
-                    FEATURE_ENABLE_HIPRI);
-            // TODO wait for HIPRI to go
-            // TODO check dns selection
-            // TODO check routes
-            if (!isWifiEnabled) {
-                disconnectFromWifi();
-            }
-        }
-    }
-
     /**
      * Exercises both registerNetworkCallback and unregisterNetworkCallback. This checks to
      * see if we get a callback for the TRANSPORT_WIFI transport type being available.
diff --git a/tests/tests/netlegacy22/Android.mk b/tests/tests/netlegacy22/Android.mk
new file mode 100644
index 0000000..68fd6f8
--- /dev/null
+++ b/tests/tests/netlegacy22/Android.mk
@@ -0,0 +1,32 @@
+# Copyright (C) 2015 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+# don't include this package in any target
+LOCAL_MODULE_TAGS := tests
+# and when built explicitly put it in the data partition
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := CtsNetTestCasesLegacyApi22
+
+LOCAL_SDK_VERSION := 22
+
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/netlegacy22/AndroidManifest.xml b/tests/tests/netlegacy22/AndroidManifest.xml
new file mode 100644
index 0000000..d243e45
--- /dev/null
+++ b/tests/tests/netlegacy22/AndroidManifest.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2007 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.cts.net.legacy22">
+
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
+    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+    <uses-permission android:name="android.permission.INTERNET" />
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="com.android.cts.net.legacy22"
+                     android:label="CTS tests of legacy android.net APIs as of API 22">
+        <meta-data android:name="listener"
+            android:value="com.android.cts.runner.CtsTestRunListener" />
+    </instrumentation>
+
+</manifest>
+
diff --git a/tests/tests/netlegacy22/src/android/net/cts/legacy/api22/ConnectivityManagerLegacyTest.java b/tests/tests/netlegacy22/src/android/net/cts/legacy/api22/ConnectivityManagerLegacyTest.java
new file mode 100644
index 0000000..8a9002b
--- /dev/null
+++ b/tests/tests/netlegacy22/src/android/net/cts/legacy/api22/ConnectivityManagerLegacyTest.java
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2015 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.net.cts.legacy.api22;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.net.ConnectivityManager;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.Network;
+import android.net.NetworkInfo;
+import android.net.wifi.WifiManager;
+import android.os.ConditionVariable;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+import java.net.DatagramSocket;
+import java.net.Inet4Address;
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.List;
+
+import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
+import static android.net.ConnectivityManager.TYPE_MOBILE;
+import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;
+import static android.net.ConnectivityManager.TYPE_VPN;
+import static android.net.ConnectivityManager.TYPE_WIFI;
+
+public class ConnectivityManagerLegacyTest extends AndroidTestCase {
+    private static final String TAG = ConnectivityManagerLegacyTest.class.getSimpleName();
+    private static final String FEATURE_ENABLE_HIPRI = "enableHIPRI";
+    private static final String HOST_ADDRESS1 = "192.0.2.1";
+    private static final String HOST_ADDRESS2 = "192.0.2.2";
+    private static final String HOST_ADDRESS3 = "192.0.2.3";
+
+    // These are correct as of API level 22, which is what we target here.
+    private static final int APN_REQUEST_FAILED = 3;
+    private static final int MAX_NETWORK_TYPE = TYPE_VPN;
+
+    private ConnectivityManager mCm;
+    private WifiManager mWifiManager;
+    private PackageManager mPackageManager;
+
+    private final List<Integer>mProtectedNetworks = new ArrayList<Integer>();
+
+    protected void setUp() throws Exception {
+        super.setUp();
+        mCm = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
+        mWifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE);
+        mPackageManager = getContext().getPackageManager();
+
+        // Get com.android.internal.R.array.config_protectedNetworks
+        int resId = getContext().getResources().getIdentifier("config_protectedNetworks", "array", "android");
+        int[] protectedNetworks = getContext().getResources().getIntArray(resId);
+        for (int p : protectedNetworks) {
+            mProtectedNetworks.add(p);
+        }
+    }
+
+    // true if only the system can turn it on
+    private boolean isNetworkProtected(int networkType) {
+        return mProtectedNetworks.contains(networkType);
+    }
+
+    private int ipv4AddrToInt(String addrString) throws Exception {
+        byte[] addr = ((Inet4Address) InetAddress.getByName(addrString)).getAddress();
+        return ((addr[3] & 0xff) << 24) | ((addr[2] & 0xff) << 16) |
+                ((addr[1] & 0xff) << 8) | (addr[0] & 0xff);
+    }
+
+    private void checkSourceAddress(String addrString, int type) throws Exception {
+        DatagramSocket d = new DatagramSocket();
+        d.connect(InetAddress.getByName(addrString), 7);
+        InetAddress localAddress = d.getLocalAddress();
+
+        Network[] networks = mCm.getAllNetworks();
+        for (int i = 0; i < networks.length; i++) {
+            NetworkInfo ni = mCm.getNetworkInfo(networks[i]);
+            if (ni != null && ni.getType() == type) {
+                LinkProperties lp = mCm.getLinkProperties(networks[i]);
+                for (LinkAddress address : lp.getLinkAddresses()) {
+                    if (address.getAddress().equals(localAddress)) {
+                        return;
+                    }
+                }
+            }
+        }
+        fail("Local address " + localAddress + " not assigned to any network of type " + type);
+    }
+
+    /** Test that hipri can be brought up when Wifi is enabled. */
+    public void testStartUsingNetworkFeature_enableHipri() throws Exception {
+        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)
+                || !mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)) {
+            // This test requires a mobile data connection and WiFi.
+            return;
+        }
+
+        // Make sure WiFi is connected to an access point.
+        connectToWifi();
+
+        expectNetworkBroadcast(TYPE_MOBILE_HIPRI, NetworkInfo.State.CONNECTED,
+                new Runnable() {
+                    public void run() {
+                        int ret = mCm.startUsingNetworkFeature(TYPE_MOBILE, FEATURE_ENABLE_HIPRI);
+                        assertTrue("Couldn't start using the HIPRI feature.", ret != -1);
+                    }
+                });
+
+        assertTrue("Couldn't requestRouteToHost using HIPRI.",
+                mCm.requestRouteToHost(TYPE_MOBILE_HIPRI, ipv4AddrToInt(HOST_ADDRESS1)));
+
+        try { Thread.sleep(1000); } catch(Exception e) {}
+        checkSourceAddress(HOST_ADDRESS1, TYPE_MOBILE);
+        checkSourceAddress(HOST_ADDRESS2, TYPE_WIFI);
+
+        // TODO check dns selection
+
+        expectNetworkBroadcast(TYPE_MOBILE_HIPRI, NetworkInfo.State.DISCONNECTED,
+                new Runnable() {
+                    public void run() {
+                        int ret = mCm.stopUsingNetworkFeature(TYPE_MOBILE, FEATURE_ENABLE_HIPRI);
+                        assertTrue("Couldn't stop using the HIPRI feature.", ret != -1);
+                    }
+                });
+
+
+        // TODO check dns selection
+        disconnectFromWifi();
+    }
+
+    public void testStartUsingNetworkFeature() {
+
+        final String invalidFeature = "invalidFeature";
+        final String mmsFeature = "enableMMS";
+        final int failureCode = -1;
+        final int wifiOnlyStartFailureCode = APN_REQUEST_FAILED;
+        final int wifiOnlyStopFailureCode = -1;
+
+        NetworkInfo ni = mCm.getNetworkInfo(TYPE_MOBILE);
+        if (ni != null) {
+            assertEquals(APN_REQUEST_FAILED,
+                    mCm.startUsingNetworkFeature(TYPE_MOBILE, invalidFeature));
+            assertEquals(failureCode, mCm.stopUsingNetworkFeature(TYPE_MOBILE, invalidFeature));
+        } else {
+            assertEquals(wifiOnlyStartFailureCode, mCm.startUsingNetworkFeature(TYPE_MOBILE,
+                    invalidFeature));
+            assertEquals(wifiOnlyStopFailureCode, mCm.stopUsingNetworkFeature(TYPE_MOBILE,
+                    invalidFeature));
+        }
+
+        ni = mCm.getNetworkInfo(TYPE_WIFI);
+        if (ni != null) {
+            // Should return failure because MMS is not supported on WIFI.
+            assertEquals(APN_REQUEST_FAILED, mCm.startUsingNetworkFeature(TYPE_WIFI,
+                    mmsFeature));
+            assertEquals(failureCode, mCm.stopUsingNetworkFeature(TYPE_WIFI,
+                    mmsFeature));
+        }
+    }
+
+    private void expectNetworkBroadcast(final int type, final NetworkInfo.State state,
+            Runnable afterWhat) {
+        final int TIMEOUT_MS = 30 * 1000;
+        final ConditionVariable var = new ConditionVariable();
+
+        Log.d(TAG, "Waiting for " + state + " broadcast for type " + type);
+        BroadcastReceiver receiver = new BroadcastReceiver() {
+            public void onReceive(Context context, Intent intent) {
+                NetworkInfo ni = intent.getExtras()
+                        .getParcelable(ConnectivityManager.EXTRA_NETWORK_INFO);
+                assertNotNull("CONNECTIVITY_ACTION with null EXTRA_NETWORK_INFO", ni);
+                if (ni.getType() == type && ni.getState().equals(state)) {
+                    Log.d(TAG, "Received expected " + state + " broadcast for type " + type);
+                    var.open();
+                }
+            }
+        };
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(CONNECTIVITY_ACTION);
+        mContext.registerReceiver(receiver, filter);
+
+        try {
+            afterWhat.run();
+            final String msg = "Did not receive expected " + state + " broadcast for type " + type +
+                    " after " + TIMEOUT_MS + " ms";
+            assertTrue(msg, var.block(TIMEOUT_MS));
+        } finally {
+            mContext.unregisterReceiver(receiver);
+        }
+    }
+
+    private boolean isWifiConnected() {
+        NetworkInfo ni = mCm.getNetworkInfo(TYPE_WIFI);
+        return ni != null && ni.isConnected();
+    }
+
+    private void setWifiState(final boolean enabled) {
+        if (enabled != isWifiConnected()) {
+            final NetworkInfo.State desiredState = enabled ?
+                    NetworkInfo.State.CONNECTED :
+                    NetworkInfo.State.DISCONNECTED;
+            expectNetworkBroadcast(TYPE_WIFI, desiredState, new Runnable() {
+                public void run() {
+                    mWifiManager.setWifiEnabled(enabled);
+                }
+            });
+        }
+    }
+
+    private void connectToWifi() {
+        setWifiState(true);
+    }
+
+    private void disconnectFromWifi() {
+        setWifiState(false);
+    }
+
+    private boolean isNetworkSupported(int networkType) {
+        return mCm.getNetworkInfo(networkType) != null;
+    }
+
+    public void testRequestRouteToHost() throws Exception {
+        for (int type = -1 ; type <= MAX_NETWORK_TYPE; type++) {
+            NetworkInfo ni = mCm.getNetworkInfo(type);
+            boolean expectToWork = isNetworkSupported(type) && !isNetworkProtected(type) &&
+                    ni != null && ni.isConnected();
+
+            try {
+                assertTrue("Network type " + type,
+                        mCm.requestRouteToHost(type, ipv4AddrToInt(HOST_ADDRESS3)) == expectToWork);
+            } catch (Exception e) {
+                Log.d(TAG, "got exception in requestRouteToHost for type " + type);
+                assertFalse("Exception received for type " + type, expectToWork);
+            }
+
+            //TODO verify route table
+        }
+
+        assertFalse(mCm.requestRouteToHost(-1, ipv4AddrToInt(HOST_ADDRESS1)));
+    }
+}