Merge "Fix ConnectivityManagerApi23Test failures and remove duplication." into qt-dev
am: ea66bf6632 Change-Id: I075b7408d2a1e1145c7a9031075e07fa1db37fed
This commit is contained in:
@@ -42,6 +42,7 @@ android_test {
|
|||||||
"FrameworksNetCommonTests",
|
"FrameworksNetCommonTests",
|
||||||
"core-tests-support",
|
"core-tests-support",
|
||||||
"compatibility-device-util-axt",
|
"compatibility-device-util-axt",
|
||||||
|
"cts-net-utils",
|
||||||
"ctstestrunner-axt",
|
"ctstestrunner-axt",
|
||||||
"ctstestserver",
|
"ctstestserver",
|
||||||
"mockwebserver",
|
"mockwebserver",
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ android_test {
|
|||||||
static_libs: [
|
static_libs: [
|
||||||
"core-tests-support",
|
"core-tests-support",
|
||||||
"compatibility-device-util-axt",
|
"compatibility-device-util-axt",
|
||||||
|
"cts-net-utils",
|
||||||
"ctstestrunner-axt",
|
"ctstestrunner-axt",
|
||||||
"ctstestserver",
|
"ctstestserver",
|
||||||
"mockwebserver",
|
"mockwebserver",
|
||||||
|
|||||||
@@ -25,58 +25,33 @@ import android.content.Intent;
|
|||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.net.ConnectivityManager;
|
import android.net.ConnectivityManager;
|
||||||
import android.net.Network;
|
import android.net.cts.util.CtsNetUtils;
|
||||||
import android.net.NetworkCapabilities;
|
|
||||||
import android.net.NetworkInfo;
|
|
||||||
import android.net.NetworkInfo.State;
|
|
||||||
import android.net.NetworkRequest;
|
|
||||||
import android.net.wifi.WifiManager;
|
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.system.Os;
|
|
||||||
import android.system.OsConstants;
|
|
||||||
import android.test.AndroidTestCase;
|
import android.test.AndroidTestCase;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.net.InetSocketAddress;
|
|
||||||
import java.net.Socket;
|
|
||||||
import java.util.concurrent.CountDownLatch;
|
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public class ConnectivityManagerApi23Test extends AndroidTestCase {
|
public class ConnectivityManagerApi23Test extends AndroidTestCase {
|
||||||
private static final String TAG = ConnectivityManagerApi23Test.class.getSimpleName();
|
private static final String TAG = ConnectivityManagerApi23Test.class.getSimpleName();
|
||||||
|
|
||||||
private static final String TEST_HOST = "connectivitycheck.gstatic.com";
|
|
||||||
private static final int SOCKET_TIMEOUT_MS = 2000;
|
|
||||||
private static final int SEND_BROADCAST_TIMEOUT = 30000;
|
private static final int SEND_BROADCAST_TIMEOUT = 30000;
|
||||||
private static final int HTTP_PORT = 80;
|
|
||||||
// Intent string to get the number of wifi CONNECTIVITY_ACTION callbacks the test app has seen
|
// Intent string to get the number of wifi CONNECTIVITY_ACTION callbacks the test app has seen
|
||||||
public static final String GET_WIFI_CONNECTIVITY_ACTION_COUNT =
|
public static final String GET_WIFI_CONNECTIVITY_ACTION_COUNT =
|
||||||
"android.net.cts.appForApi23.getWifiConnectivityActionCount";
|
"android.net.cts.appForApi23.getWifiConnectivityActionCount";
|
||||||
// Action sent to ConnectivityActionReceiver when a network callback is sent via PendingIntent.
|
// Action sent to ConnectivityActionReceiver when a network callback is sent via PendingIntent.
|
||||||
private static final String NETWORK_CALLBACK_ACTION =
|
|
||||||
"ConnectivityManagerTest.NetworkCallbackAction";
|
|
||||||
private static final String HTTP_REQUEST =
|
|
||||||
"GET /generate_204 HTTP/1.0\r\n" +
|
|
||||||
"Host: " + TEST_HOST + "\r\n" +
|
|
||||||
"Connection: keep-alive\r\n\r\n";
|
|
||||||
|
|
||||||
private Context mContext;
|
private Context mContext;
|
||||||
private ConnectivityManager mCm;
|
|
||||||
private WifiManager mWifiManager;
|
|
||||||
private PackageManager mPackageManager;
|
private PackageManager mPackageManager;
|
||||||
|
private CtsNetUtils mCtsNetUtils;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void setUp() throws Exception {
|
protected void setUp() throws Exception {
|
||||||
super.setUp();
|
super.setUp();
|
||||||
Looper.prepare();
|
Looper.prepare();
|
||||||
mContext = getContext();
|
mContext = getContext();
|
||||||
mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
|
|
||||||
mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
|
|
||||||
mPackageManager = mContext.getPackageManager();
|
mPackageManager = mContext.getPackageManager();
|
||||||
|
mCtsNetUtils = new CtsNetUtils(mContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -89,7 +64,7 @@ public class ConnectivityManagerApi23Test extends AndroidTestCase {
|
|||||||
}
|
}
|
||||||
ConnectivityReceiver.prepare();
|
ConnectivityReceiver.prepare();
|
||||||
|
|
||||||
toggleWifi();
|
mCtsNetUtils.toggleWifi();
|
||||||
|
|
||||||
// The connectivity broadcast has been sent; push through a terminal broadcast
|
// The connectivity broadcast has been sent; push through a terminal broadcast
|
||||||
// to wait for in the receive to confirm it didn't see the connectivity change.
|
// to wait for in the receive to confirm it didn't see the connectivity change.
|
||||||
@@ -112,7 +87,7 @@ public class ConnectivityManagerApi23Test extends AndroidTestCase {
|
|||||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
|
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
|
||||||
Thread.sleep(200);
|
Thread.sleep(200);
|
||||||
|
|
||||||
toggleWifi();
|
mCtsNetUtils.toggleWifi();
|
||||||
|
|
||||||
Intent getConnectivityCount = new Intent(GET_WIFI_CONNECTIVITY_ACTION_COUNT);
|
Intent getConnectivityCount = new Intent(GET_WIFI_CONNECTIVITY_ACTION_COUNT);
|
||||||
assertEquals(2, sendOrderedBroadcastAndReturnResultCode(
|
assertEquals(2, sendOrderedBroadcastAndReturnResultCode(
|
||||||
@@ -130,7 +105,7 @@ public class ConnectivityManagerApi23Test extends AndroidTestCase {
|
|||||||
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
|
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
|
||||||
mContext.registerReceiver(receiver, filter);
|
mContext.registerReceiver(receiver, filter);
|
||||||
|
|
||||||
toggleWifi();
|
mCtsNetUtils.toggleWifi();
|
||||||
Intent finalIntent = new Intent(ConnectivityReceiver.FINAL_ACTION);
|
Intent finalIntent = new Intent(ConnectivityReceiver.FINAL_ACTION);
|
||||||
finalIntent.setClass(mContext, ConnectivityReceiver.class);
|
finalIntent.setClass(mContext, ConnectivityReceiver.class);
|
||||||
mContext.sendBroadcast(finalIntent);
|
mContext.sendBroadcast(finalIntent);
|
||||||
@@ -138,19 +113,6 @@ public class ConnectivityManagerApi23Test extends AndroidTestCase {
|
|||||||
assertTrue(ConnectivityReceiver.waitForBroadcast());
|
assertTrue(ConnectivityReceiver.waitForBroadcast());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Toggle WiFi twice, leaving it in the state it started in
|
|
||||||
private void toggleWifi() {
|
|
||||||
if (mWifiManager.isWifiEnabled()) {
|
|
||||||
Network wifiNetwork = getWifiNetwork();
|
|
||||||
disconnectFromWifi(wifiNetwork);
|
|
||||||
connectToWifi();
|
|
||||||
} else {
|
|
||||||
connectToWifi();
|
|
||||||
Network wifiNetwork = getWifiNetwork();
|
|
||||||
disconnectFromWifi(wifiNetwork);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int sendOrderedBroadcastAndReturnResultCode(
|
private int sendOrderedBroadcastAndReturnResultCode(
|
||||||
Intent intent, int timeoutMs) throws InterruptedException {
|
Intent intent, int timeoutMs) throws InterruptedException {
|
||||||
final LinkedBlockingQueue<Integer> result = new LinkedBlockingQueue<>(1);
|
final LinkedBlockingQueue<Integer> result = new LinkedBlockingQueue<>(1);
|
||||||
@@ -167,233 +129,4 @@ public class ConnectivityManagerApi23Test extends AndroidTestCase {
|
|||||||
return resultCode;
|
return resultCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Network getWifiNetwork() {
|
|
||||||
TestNetworkCallback callback = new TestNetworkCallback();
|
|
||||||
mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback);
|
|
||||||
Network network = null;
|
|
||||||
try {
|
|
||||||
network = callback.waitForAvailable();
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
fail("NetworkCallback wait was interrupted.");
|
|
||||||
} finally {
|
|
||||||
mCm.unregisterNetworkCallback(callback);
|
|
||||||
}
|
|
||||||
assertNotNull("Cannot find Network for wifi. Is wifi connected?", network);
|
|
||||||
return network;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Disable WiFi and wait for it to become disconnected from the network. */
|
|
||||||
private void disconnectFromWifi(Network wifiNetworkToCheck) {
|
|
||||||
final TestNetworkCallback callback = new TestNetworkCallback();
|
|
||||||
mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback);
|
|
||||||
Network lostWifiNetwork = null;
|
|
||||||
|
|
||||||
ConnectivityActionReceiver receiver = new ConnectivityActionReceiver(
|
|
||||||
ConnectivityManager.TYPE_WIFI, NetworkInfo.State.DISCONNECTED);
|
|
||||||
IntentFilter filter = new IntentFilter();
|
|
||||||
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
|
|
||||||
mContext.registerReceiver(receiver, filter);
|
|
||||||
|
|
||||||
// Assert that we can establish a TCP connection on wifi.
|
|
||||||
Socket wifiBoundSocket = null;
|
|
||||||
if (wifiNetworkToCheck != null) {
|
|
||||||
try {
|
|
||||||
wifiBoundSocket = getBoundSocket(wifiNetworkToCheck, TEST_HOST, HTTP_PORT);
|
|
||||||
testHttpRequest(wifiBoundSocket);
|
|
||||||
} catch (IOException e) {
|
|
||||||
fail("HTTP request before wifi disconnected failed with: " + e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean disconnected = false;
|
|
||||||
try {
|
|
||||||
assertTrue(mWifiManager.setWifiEnabled(false));
|
|
||||||
// Ensure we get both an onLost callback and a CONNECTIVITY_ACTION.
|
|
||||||
lostWifiNetwork = callback.waitForLost();
|
|
||||||
assertNotNull(lostWifiNetwork);
|
|
||||||
disconnected = receiver.waitForState();
|
|
||||||
} catch (InterruptedException ex) {
|
|
||||||
fail("disconnectFromWifi was interrupted");
|
|
||||||
} finally {
|
|
||||||
mCm.unregisterNetworkCallback(callback);
|
|
||||||
mContext.unregisterReceiver(receiver);
|
|
||||||
}
|
|
||||||
|
|
||||||
assertTrue("Wifi failed to reach DISCONNECTED state.", disconnected);
|
|
||||||
|
|
||||||
// Check that the socket is closed when wifi disconnects.
|
|
||||||
if (wifiBoundSocket != null) {
|
|
||||||
try {
|
|
||||||
testHttpRequest(wifiBoundSocket);
|
|
||||||
fail("HTTP request should not succeed after wifi disconnects");
|
|
||||||
} catch (IOException expected) {
|
|
||||||
assertEquals(Os.strerror(OsConstants.ECONNABORTED), expected.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Enable WiFi and wait for it to become connected to a network. */
|
|
||||||
private Network connectToWifi() {
|
|
||||||
final TestNetworkCallback callback = new TestNetworkCallback();
|
|
||||||
mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback);
|
|
||||||
Network wifiNetwork = null;
|
|
||||||
|
|
||||||
ConnectivityActionReceiver receiver = new ConnectivityActionReceiver(
|
|
||||||
ConnectivityManager.TYPE_WIFI, NetworkInfo.State.CONNECTED);
|
|
||||||
IntentFilter filter = new IntentFilter();
|
|
||||||
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
|
|
||||||
mContext.registerReceiver(receiver, filter);
|
|
||||||
|
|
||||||
boolean connected = false;
|
|
||||||
try {
|
|
||||||
assertTrue(mWifiManager.setWifiEnabled(true));
|
|
||||||
// Ensure we get both an onAvailable callback and a CONNECTIVITY_ACTION.
|
|
||||||
wifiNetwork = callback.waitForAvailable();
|
|
||||||
assertNotNull(wifiNetwork);
|
|
||||||
connected = receiver.waitForState();
|
|
||||||
} catch (InterruptedException ex) {
|
|
||||||
fail("connectToWifi was interrupted");
|
|
||||||
} finally {
|
|
||||||
mCm.unregisterNetworkCallback(callback);
|
|
||||||
mContext.unregisterReceiver(receiver);
|
|
||||||
}
|
|
||||||
|
|
||||||
assertTrue("Wifi must be configured to connect to an access point for this test.",
|
|
||||||
connected);
|
|
||||||
return wifiNetwork;
|
|
||||||
}
|
|
||||||
|
|
||||||
private NetworkRequest makeWifiNetworkRequest() {
|
|
||||||
return new NetworkRequest.Builder()
|
|
||||||
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void testHttpRequest(Socket s) throws IOException {
|
|
||||||
OutputStream out = s.getOutputStream();
|
|
||||||
InputStream in = s.getInputStream();
|
|
||||||
|
|
||||||
final byte[] requestBytes = HTTP_REQUEST.getBytes("UTF-8");
|
|
||||||
byte[] responseBytes = new byte[4096];
|
|
||||||
out.write(requestBytes);
|
|
||||||
in.read(responseBytes);
|
|
||||||
assertTrue(new String(responseBytes, "UTF-8").startsWith("HTTP/1.0 204 No Content\r\n"));
|
|
||||||
}
|
|
||||||
|
|
||||||
private Socket getBoundSocket(Network network, String host, int port) throws IOException {
|
|
||||||
InetSocketAddress addr = new InetSocketAddress(host, port);
|
|
||||||
Socket s = network.getSocketFactory().createSocket();
|
|
||||||
try {
|
|
||||||
s.setSoTimeout(SOCKET_TIMEOUT_MS);
|
|
||||||
s.connect(addr, SOCKET_TIMEOUT_MS);
|
|
||||||
} catch (IOException e) {
|
|
||||||
s.close();
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Receiver that captures the last connectivity change's network type and state. Recognizes
|
|
||||||
* both {@code CONNECTIVITY_ACTION} and {@code NETWORK_CALLBACK_ACTION} intents.
|
|
||||||
*/
|
|
||||||
private class ConnectivityActionReceiver extends BroadcastReceiver {
|
|
||||||
|
|
||||||
private final CountDownLatch mReceiveLatch = new CountDownLatch(1);
|
|
||||||
|
|
||||||
private final int mNetworkType;
|
|
||||||
private final NetworkInfo.State mNetState;
|
|
||||||
|
|
||||||
ConnectivityActionReceiver(int networkType, NetworkInfo.State netState) {
|
|
||||||
mNetworkType = networkType;
|
|
||||||
mNetState = netState;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onReceive(Context context, Intent intent) {
|
|
||||||
String action = intent.getAction();
|
|
||||||
NetworkInfo networkInfo = null;
|
|
||||||
|
|
||||||
// When receiving ConnectivityManager.CONNECTIVITY_ACTION, the NetworkInfo parcelable
|
|
||||||
// is stored in EXTRA_NETWORK_INFO. With a NETWORK_CALLBACK_ACTION, the Network is
|
|
||||||
// sent in EXTRA_NETWORK and we need to ask the ConnectivityManager for the NetworkInfo.
|
|
||||||
if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) {
|
|
||||||
networkInfo = intent.getExtras()
|
|
||||||
.getParcelable(ConnectivityManager.EXTRA_NETWORK_INFO);
|
|
||||||
assertNotNull("ConnectivityActionReceiver expected EXTRA_NETWORK_INFO", networkInfo);
|
|
||||||
} else if (NETWORK_CALLBACK_ACTION.equals(action)) {
|
|
||||||
Network network = intent.getExtras()
|
|
||||||
.getParcelable(ConnectivityManager.EXTRA_NETWORK);
|
|
||||||
assertNotNull("ConnectivityActionReceiver expected EXTRA_NETWORK", network);
|
|
||||||
networkInfo = mCm.getNetworkInfo(network);
|
|
||||||
if (networkInfo == null) {
|
|
||||||
// When disconnecting, it seems like we get an intent sent with an invalid
|
|
||||||
// Network; that is, by the time we call ConnectivityManager.getNetworkInfo(),
|
|
||||||
// it is invalid. Ignore these.
|
|
||||||
Log.i(TAG, "ConnectivityActionReceiver NETWORK_CALLBACK_ACTION ignoring "
|
|
||||||
+ "invalid network");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fail("ConnectivityActionReceiver received unxpected intent action: " + action);
|
|
||||||
}
|
|
||||||
|
|
||||||
assertNotNull("ConnectivityActionReceiver didn't find NetworkInfo", networkInfo);
|
|
||||||
int networkType = networkInfo.getType();
|
|
||||||
State networkState = networkInfo.getState();
|
|
||||||
Log.i(TAG, "Network type: " + networkType + " state: " + networkState);
|
|
||||||
if (networkType == mNetworkType && networkInfo.getState() == mNetState) {
|
|
||||||
mReceiveLatch.countDown();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean waitForState() throws InterruptedException {
|
|
||||||
return mReceiveLatch.await(30, TimeUnit.SECONDS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback used in testRegisterNetworkCallback that allows caller to block on
|
|
||||||
* {@code onAvailable}.
|
|
||||||
*/
|
|
||||||
private static class TestNetworkCallback extends ConnectivityManager.NetworkCallback {
|
|
||||||
private final CountDownLatch mAvailableLatch = new CountDownLatch(1);
|
|
||||||
private final CountDownLatch mLostLatch = new CountDownLatch(1);
|
|
||||||
private final CountDownLatch mUnavailableLatch = new CountDownLatch(1);
|
|
||||||
|
|
||||||
public Network currentNetwork;
|
|
||||||
public Network lastLostNetwork;
|
|
||||||
|
|
||||||
public Network waitForAvailable() throws InterruptedException {
|
|
||||||
return mAvailableLatch.await(30, TimeUnit.SECONDS) ? currentNetwork : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Network waitForLost() throws InterruptedException {
|
|
||||||
return mLostLatch.await(30, TimeUnit.SECONDS) ? lastLostNetwork : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean waitForUnavailable() throws InterruptedException {
|
|
||||||
return mUnavailableLatch.await(2, TimeUnit.SECONDS);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAvailable(Network network) {
|
|
||||||
currentNetwork = network;
|
|
||||||
mAvailableLatch.countDown();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onLost(Network network) {
|
|
||||||
lastLostNetwork = network;
|
|
||||||
if (network.equals(currentNetwork)) {
|
|
||||||
currentNetwork = null;
|
|
||||||
}
|
|
||||||
mLostLatch.countDown();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onUnavailable() {
|
|
||||||
mUnavailableLatch.countDown();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -21,8 +21,12 @@ import static android.content.pm.PackageManager.FEATURE_WIFI;
|
|||||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS;
|
import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS;
|
||||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
|
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
|
||||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
|
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
|
||||||
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
|
|
||||||
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
|
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
|
||||||
|
import static android.net.cts.util.CtsNetUtils.ConnectivityActionReceiver;
|
||||||
|
import static android.net.cts.util.CtsNetUtils.HTTP_PORT;
|
||||||
|
import static android.net.cts.util.CtsNetUtils.NETWORK_CALLBACK_ACTION;
|
||||||
|
import static android.net.cts.util.CtsNetUtils.TEST_HOST;
|
||||||
|
import static android.net.cts.util.CtsNetUtils.TestNetworkCallback;
|
||||||
import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT;
|
import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT;
|
||||||
import static android.provider.Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE;
|
import static android.provider.Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE;
|
||||||
import static android.system.OsConstants.AF_INET;
|
import static android.system.OsConstants.AF_INET;
|
||||||
@@ -34,7 +38,6 @@ import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
|
|||||||
import android.app.Instrumentation;
|
import android.app.Instrumentation;
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.app.UiAutomation;
|
import android.app.UiAutomation;
|
||||||
import android.content.BroadcastReceiver;
|
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
@@ -53,6 +56,7 @@ import android.net.NetworkInfo.DetailedState;
|
|||||||
import android.net.NetworkInfo.State;
|
import android.net.NetworkInfo.State;
|
||||||
import android.net.NetworkRequest;
|
import android.net.NetworkRequest;
|
||||||
import android.net.SocketKeepalive;
|
import android.net.SocketKeepalive;
|
||||||
|
import android.net.cts.util.CtsNetUtils;
|
||||||
import android.net.util.KeepaliveUtils;
|
import android.net.util.KeepaliveUtils;
|
||||||
import android.net.wifi.WifiManager;
|
import android.net.wifi.WifiManager;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
@@ -61,15 +65,12 @@ import android.os.SystemClock;
|
|||||||
import android.os.SystemProperties;
|
import android.os.SystemProperties;
|
||||||
import android.platform.test.annotations.AppModeFull;
|
import android.platform.test.annotations.AppModeFull;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.system.Os;
|
|
||||||
import android.system.OsConstants;
|
|
||||||
import android.test.AndroidTestCase;
|
import android.test.AndroidTestCase;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.test.InstrumentationRegistry;
|
import androidx.test.InstrumentationRegistry;
|
||||||
|
|
||||||
import com.android.compatibility.common.util.SystemUtil;
|
|
||||||
import com.android.internal.R;
|
import com.android.internal.R;
|
||||||
import com.android.internal.telephony.PhoneConstants;
|
import com.android.internal.telephony.PhoneConstants;
|
||||||
|
|
||||||
@@ -107,8 +108,6 @@ public class ConnectivityManagerTest extends AndroidTestCase {
|
|||||||
public static final int TYPE_WIFI = ConnectivityManager.TYPE_WIFI;
|
public static final int TYPE_WIFI = ConnectivityManager.TYPE_WIFI;
|
||||||
|
|
||||||
private static final int HOST_ADDRESS = 0x7f000001;// represent ip 127.0.0.1
|
private static final int HOST_ADDRESS = 0x7f000001;// represent ip 127.0.0.1
|
||||||
private static final String TEST_HOST = "connectivitycheck.gstatic.com";
|
|
||||||
private static final int SOCKET_TIMEOUT_MS = 2000;
|
|
||||||
private static final int CONNECT_TIMEOUT_MS = 2000;
|
private static final int CONNECT_TIMEOUT_MS = 2000;
|
||||||
private static final int KEEPALIVE_CALLBACK_TIMEOUT_MS = 2000;
|
private static final int KEEPALIVE_CALLBACK_TIMEOUT_MS = 2000;
|
||||||
private static final int KEEPALIVE_SOCKET_TIMEOUT_MS = 5000;
|
private static final int KEEPALIVE_SOCKET_TIMEOUT_MS = 5000;
|
||||||
@@ -116,16 +115,6 @@ public class ConnectivityManagerTest extends AndroidTestCase {
|
|||||||
private static final int NETWORK_CHANGE_METEREDNESS_TIMEOUT = 5000;
|
private static final int NETWORK_CHANGE_METEREDNESS_TIMEOUT = 5000;
|
||||||
private static final int NUM_TRIES_MULTIPATH_PREF_CHECK = 20;
|
private static final int NUM_TRIES_MULTIPATH_PREF_CHECK = 20;
|
||||||
private static final long INTERVAL_MULTIPATH_PREF_CHECK_MS = 500;
|
private static final long INTERVAL_MULTIPATH_PREF_CHECK_MS = 500;
|
||||||
private static final int HTTP_PORT = 80;
|
|
||||||
private static final String HTTP_REQUEST =
|
|
||||||
"GET /generate_204 HTTP/1.0\r\n" +
|
|
||||||
"Host: " + TEST_HOST + "\r\n" +
|
|
||||||
"Connection: keep-alive\r\n\r\n";
|
|
||||||
|
|
||||||
// Action sent to ConnectivityActionReceiver when a network callback is sent via PendingIntent.
|
|
||||||
private static final String NETWORK_CALLBACK_ACTION =
|
|
||||||
"ConnectivityManagerTest.NetworkCallbackAction";
|
|
||||||
|
|
||||||
// device could have only one interface: data, wifi.
|
// device could have only one interface: data, wifi.
|
||||||
private static final int MIN_NUM_NETWORK_TYPES = 1;
|
private static final int MIN_NUM_NETWORK_TYPES = 1;
|
||||||
|
|
||||||
@@ -137,8 +126,8 @@ public class ConnectivityManagerTest extends AndroidTestCase {
|
|||||||
private final HashMap<Integer, NetworkConfig> mNetworks =
|
private final HashMap<Integer, NetworkConfig> mNetworks =
|
||||||
new HashMap<Integer, NetworkConfig>();
|
new HashMap<Integer, NetworkConfig>();
|
||||||
boolean mWifiConnectAttempted;
|
boolean mWifiConnectAttempted;
|
||||||
private TestNetworkCallback mCellNetworkCallback;
|
|
||||||
private UiAutomation mUiAutomation;
|
private UiAutomation mUiAutomation;
|
||||||
|
private CtsNetUtils mCtsNetUtils;
|
||||||
private boolean mShellPermissionIdentityAdopted;
|
private boolean mShellPermissionIdentityAdopted;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -150,6 +139,7 @@ public class ConnectivityManagerTest extends AndroidTestCase {
|
|||||||
mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
|
mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||||
mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
|
mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
|
||||||
mPackageManager = mContext.getPackageManager();
|
mPackageManager = mContext.getPackageManager();
|
||||||
|
mCtsNetUtils = new CtsNetUtils(mContext);
|
||||||
mWifiConnectAttempted = false;
|
mWifiConnectAttempted = false;
|
||||||
|
|
||||||
// Get com.android.internal.R.array.networkAttributes
|
// Get com.android.internal.R.array.networkAttributes
|
||||||
@@ -174,10 +164,10 @@ public class ConnectivityManagerTest extends AndroidTestCase {
|
|||||||
protected void tearDown() throws Exception {
|
protected void tearDown() throws Exception {
|
||||||
// Return WiFi to its original disabled state after tests that explicitly connect.
|
// Return WiFi to its original disabled state after tests that explicitly connect.
|
||||||
if (mWifiConnectAttempted) {
|
if (mWifiConnectAttempted) {
|
||||||
disconnectFromWifi(null);
|
mCtsNetUtils.disconnectFromWifi(null);
|
||||||
}
|
}
|
||||||
if (cellConnectAttempted()) {
|
if (mCtsNetUtils.cellConnectAttempted()) {
|
||||||
disconnectFromCell();
|
mCtsNetUtils.disconnectFromCell();
|
||||||
}
|
}
|
||||||
dropShellPermissionIdentity();
|
dropShellPermissionIdentity();
|
||||||
super.tearDown();
|
super.tearDown();
|
||||||
@@ -190,10 +180,10 @@ public class ConnectivityManagerTest extends AndroidTestCase {
|
|||||||
*/
|
*/
|
||||||
private Network ensureWifiConnected() {
|
private Network ensureWifiConnected() {
|
||||||
if (mWifiManager.isWifiEnabled()) {
|
if (mWifiManager.isWifiEnabled()) {
|
||||||
return getWifiNetwork();
|
return mCtsNetUtils.getWifiNetwork();
|
||||||
}
|
}
|
||||||
mWifiConnectAttempted = true;
|
mWifiConnectAttempted = true;
|
||||||
return connectToWifi();
|
return mCtsNetUtils.connectToWifi();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testIsNetworkTypeValid() {
|
public void testIsNetworkTypeValid() {
|
||||||
@@ -301,8 +291,8 @@ public class ConnectivityManagerTest extends AndroidTestCase {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Network wifiNetwork = connectToWifi();
|
Network wifiNetwork = mCtsNetUtils.connectToWifi();
|
||||||
Network cellNetwork = connectToCell();
|
Network cellNetwork = mCtsNetUtils.connectToCell();
|
||||||
// This server returns the requestor's IP address as the response body.
|
// This server returns the requestor's IP address as the response body.
|
||||||
URL url = new URL("http://google-ipv6test.appspot.com/ip.js?fmt=text");
|
URL url = new URL("http://google-ipv6test.appspot.com/ip.js?fmt=text");
|
||||||
String wifiAddressString = httpGet(wifiNetwork, url);
|
String wifiAddressString = httpGet(wifiNetwork, url);
|
||||||
@@ -320,33 +310,6 @@ public class ConnectivityManagerTest extends AndroidTestCase {
|
|||||||
assertFalse("Unexpectedly equal: " + wifiNetwork, wifiNetwork.equals(cellNetwork));
|
assertFalse("Unexpectedly equal: " + wifiNetwork, wifiNetwork.equals(cellNetwork));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Network connectToCell() throws InterruptedException {
|
|
||||||
if (cellConnectAttempted()) {
|
|
||||||
throw new IllegalStateException("Already connected");
|
|
||||||
}
|
|
||||||
NetworkRequest cellRequest = new NetworkRequest.Builder()
|
|
||||||
.addTransportType(TRANSPORT_CELLULAR)
|
|
||||||
.addCapability(NET_CAPABILITY_INTERNET)
|
|
||||||
.build();
|
|
||||||
mCellNetworkCallback = new TestNetworkCallback();
|
|
||||||
mCm.requestNetwork(cellRequest, mCellNetworkCallback);
|
|
||||||
final Network cellNetwork = mCellNetworkCallback.waitForAvailable();
|
|
||||||
assertNotNull("Cell network not available within timeout", cellNetwork);
|
|
||||||
return cellNetwork;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean cellConnectAttempted() {
|
|
||||||
return mCellNetworkCallback != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void disconnectFromCell() {
|
|
||||||
if (!cellConnectAttempted()) {
|
|
||||||
throw new IllegalStateException("Cell connection not attempted");
|
|
||||||
}
|
|
||||||
mCm.unregisterNetworkCallback(mCellNetworkCallback);
|
|
||||||
mCellNetworkCallback = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs a HTTP GET to the specified URL on the specified Network, and returns
|
* Performs a HTTP GET to the specified URL on the specified Network, and returns
|
||||||
* the response body decoded as UTF-8.
|
* the response body decoded as UTF-8.
|
||||||
@@ -508,7 +471,7 @@ public class ConnectivityManagerTest extends AndroidTestCase {
|
|||||||
filter.addAction(NETWORK_CALLBACK_ACTION);
|
filter.addAction(NETWORK_CALLBACK_ACTION);
|
||||||
|
|
||||||
ConnectivityActionReceiver receiver = new ConnectivityActionReceiver(
|
ConnectivityActionReceiver receiver = new ConnectivityActionReceiver(
|
||||||
ConnectivityManager.TYPE_WIFI, NetworkInfo.State.CONNECTED);
|
mCm, ConnectivityManager.TYPE_WIFI, NetworkInfo.State.CONNECTED);
|
||||||
mContext.registerReceiver(receiver, filter);
|
mContext.registerReceiver(receiver, filter);
|
||||||
|
|
||||||
// Create a broadcast PendingIntent for NETWORK_CALLBACK_ACTION.
|
// Create a broadcast PendingIntent for NETWORK_CALLBACK_ACTION.
|
||||||
@@ -567,7 +530,7 @@ public class ConnectivityManagerTest extends AndroidTestCase {
|
|||||||
public void testRequestNetworkCallback_onUnavailable() {
|
public void testRequestNetworkCallback_onUnavailable() {
|
||||||
final boolean previousWifiEnabledState = mWifiManager.isWifiEnabled();
|
final boolean previousWifiEnabledState = mWifiManager.isWifiEnabled();
|
||||||
if (previousWifiEnabledState) {
|
if (previousWifiEnabledState) {
|
||||||
disconnectFromWifi(null);
|
mCtsNetUtils.disconnectFromWifi(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
final TestNetworkCallback callback = new TestNetworkCallback();
|
final TestNetworkCallback callback = new TestNetworkCallback();
|
||||||
@@ -584,42 +547,11 @@ public class ConnectivityManagerTest extends AndroidTestCase {
|
|||||||
} finally {
|
} finally {
|
||||||
mCm.unregisterNetworkCallback(callback);
|
mCm.unregisterNetworkCallback(callback);
|
||||||
if (previousWifiEnabledState) {
|
if (previousWifiEnabledState) {
|
||||||
connectToWifi();
|
mCtsNetUtils.connectToWifi();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Enable WiFi and wait for it to become connected to a network. */
|
|
||||||
private Network connectToWifi() {
|
|
||||||
final TestNetworkCallback callback = new TestNetworkCallback();
|
|
||||||
mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback);
|
|
||||||
Network wifiNetwork = null;
|
|
||||||
|
|
||||||
ConnectivityActionReceiver receiver = new ConnectivityActionReceiver(
|
|
||||||
ConnectivityManager.TYPE_WIFI, NetworkInfo.State.CONNECTED);
|
|
||||||
IntentFilter filter = new IntentFilter();
|
|
||||||
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
|
|
||||||
mContext.registerReceiver(receiver, filter);
|
|
||||||
|
|
||||||
boolean connected = false;
|
|
||||||
try {
|
|
||||||
SystemUtil.runShellCommand("svc wifi enable");
|
|
||||||
// Ensure we get both an onAvailable callback and a CONNECTIVITY_ACTION.
|
|
||||||
wifiNetwork = callback.waitForAvailable();
|
|
||||||
assertNotNull(wifiNetwork);
|
|
||||||
connected = receiver.waitForState();
|
|
||||||
} catch (InterruptedException ex) {
|
|
||||||
fail("connectToWifi was interrupted");
|
|
||||||
} finally {
|
|
||||||
mCm.unregisterNetworkCallback(callback);
|
|
||||||
mContext.unregisterReceiver(receiver);
|
|
||||||
}
|
|
||||||
|
|
||||||
assertTrue("Wifi must be configured to connect to an access point for this test.",
|
|
||||||
connected);
|
|
||||||
return wifiNetwork;
|
|
||||||
}
|
|
||||||
|
|
||||||
private InetAddress getFirstV4Address(Network network) {
|
private InetAddress getFirstV4Address(Network network) {
|
||||||
LinkProperties linkProperties = mCm.getLinkProperties(network);
|
LinkProperties linkProperties = mCm.getLinkProperties(network);
|
||||||
for (InetAddress address : linkProperties.getAddresses()) {
|
for (InetAddress address : linkProperties.getAddresses()) {
|
||||||
@@ -630,199 +562,6 @@ public class ConnectivityManagerTest extends AndroidTestCase {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Socket getBoundSocket(Network network, String host, int port) throws IOException {
|
|
||||||
InetSocketAddress addr = new InetSocketAddress(host, port);
|
|
||||||
Socket s = network.getSocketFactory().createSocket();
|
|
||||||
try {
|
|
||||||
s.setSoTimeout(SOCKET_TIMEOUT_MS);
|
|
||||||
s.connect(addr, SOCKET_TIMEOUT_MS);
|
|
||||||
} catch (IOException e) {
|
|
||||||
s.close();
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void testHttpRequest(Socket s) throws IOException {
|
|
||||||
OutputStream out = s.getOutputStream();
|
|
||||||
InputStream in = s.getInputStream();
|
|
||||||
|
|
||||||
final byte[] requestBytes = HTTP_REQUEST.getBytes("UTF-8");
|
|
||||||
byte[] responseBytes = new byte[4096];
|
|
||||||
out.write(requestBytes);
|
|
||||||
in.read(responseBytes);
|
|
||||||
assertTrue(new String(responseBytes, "UTF-8").startsWith("HTTP/1.0 204 No Content\r\n"));
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Disable WiFi and wait for it to become disconnected from the network. */
|
|
||||||
private void disconnectFromWifi(Network wifiNetworkToCheck) {
|
|
||||||
final TestNetworkCallback callback = new TestNetworkCallback();
|
|
||||||
mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback);
|
|
||||||
Network lostWifiNetwork = null;
|
|
||||||
|
|
||||||
ConnectivityActionReceiver receiver = new ConnectivityActionReceiver(
|
|
||||||
ConnectivityManager.TYPE_WIFI, NetworkInfo.State.DISCONNECTED);
|
|
||||||
IntentFilter filter = new IntentFilter();
|
|
||||||
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
|
|
||||||
mContext.registerReceiver(receiver, filter);
|
|
||||||
|
|
||||||
// Assert that we can establish a TCP connection on wifi.
|
|
||||||
Socket wifiBoundSocket = null;
|
|
||||||
if (wifiNetworkToCheck != null) {
|
|
||||||
try {
|
|
||||||
wifiBoundSocket = getBoundSocket(wifiNetworkToCheck, TEST_HOST, HTTP_PORT);
|
|
||||||
testHttpRequest(wifiBoundSocket);
|
|
||||||
} catch (IOException e) {
|
|
||||||
fail("HTTP request before wifi disconnected failed with: " + e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean disconnected = false;
|
|
||||||
try {
|
|
||||||
SystemUtil.runShellCommand("svc wifi disable");
|
|
||||||
// Ensure we get both an onLost callback and a CONNECTIVITY_ACTION.
|
|
||||||
lostWifiNetwork = callback.waitForLost();
|
|
||||||
assertNotNull(lostWifiNetwork);
|
|
||||||
disconnected = receiver.waitForState();
|
|
||||||
} catch (InterruptedException ex) {
|
|
||||||
fail("disconnectFromWifi was interrupted");
|
|
||||||
} finally {
|
|
||||||
mCm.unregisterNetworkCallback(callback);
|
|
||||||
mContext.unregisterReceiver(receiver);
|
|
||||||
}
|
|
||||||
|
|
||||||
assertTrue("Wifi failed to reach DISCONNECTED state.", disconnected);
|
|
||||||
|
|
||||||
// Check that the socket is closed when wifi disconnects.
|
|
||||||
if (wifiBoundSocket != null) {
|
|
||||||
try {
|
|
||||||
testHttpRequest(wifiBoundSocket);
|
|
||||||
fail("HTTP request should not succeed after wifi disconnects");
|
|
||||||
} catch (IOException expected) {
|
|
||||||
assertEquals(Os.strerror(OsConstants.ECONNABORTED), expected.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Receiver that captures the last connectivity change's network type and state. Recognizes
|
|
||||||
* both {@code CONNECTIVITY_ACTION} and {@code NETWORK_CALLBACK_ACTION} intents.
|
|
||||||
*/
|
|
||||||
private class ConnectivityActionReceiver extends BroadcastReceiver {
|
|
||||||
|
|
||||||
private final CountDownLatch mReceiveLatch = new CountDownLatch(1);
|
|
||||||
|
|
||||||
private final int mNetworkType;
|
|
||||||
private final NetworkInfo.State mNetState;
|
|
||||||
|
|
||||||
ConnectivityActionReceiver(int networkType, NetworkInfo.State netState) {
|
|
||||||
mNetworkType = networkType;
|
|
||||||
mNetState = netState;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onReceive(Context context, Intent intent) {
|
|
||||||
String action = intent.getAction();
|
|
||||||
NetworkInfo networkInfo = null;
|
|
||||||
|
|
||||||
// When receiving ConnectivityManager.CONNECTIVITY_ACTION, the NetworkInfo parcelable
|
|
||||||
// is stored in EXTRA_NETWORK_INFO. With a NETWORK_CALLBACK_ACTION, the Network is
|
|
||||||
// sent in EXTRA_NETWORK and we need to ask the ConnectivityManager for the NetworkInfo.
|
|
||||||
if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) {
|
|
||||||
networkInfo = intent.getExtras()
|
|
||||||
.getParcelable(ConnectivityManager.EXTRA_NETWORK_INFO);
|
|
||||||
assertNotNull("ConnectivityActionReceiver expected EXTRA_NETWORK_INFO", networkInfo);
|
|
||||||
} else if (NETWORK_CALLBACK_ACTION.equals(action)) {
|
|
||||||
Network network = intent.getExtras()
|
|
||||||
.getParcelable(ConnectivityManager.EXTRA_NETWORK);
|
|
||||||
assertNotNull("ConnectivityActionReceiver expected EXTRA_NETWORK", network);
|
|
||||||
networkInfo = mCm.getNetworkInfo(network);
|
|
||||||
if (networkInfo == null) {
|
|
||||||
// When disconnecting, it seems like we get an intent sent with an invalid
|
|
||||||
// Network; that is, by the time we call ConnectivityManager.getNetworkInfo(),
|
|
||||||
// it is invalid. Ignore these.
|
|
||||||
Log.i(TAG, "ConnectivityActionReceiver NETWORK_CALLBACK_ACTION ignoring "
|
|
||||||
+ "invalid network");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fail("ConnectivityActionReceiver received unxpected intent action: " + action);
|
|
||||||
}
|
|
||||||
|
|
||||||
assertNotNull("ConnectivityActionReceiver didn't find NetworkInfo", networkInfo);
|
|
||||||
int networkType = networkInfo.getType();
|
|
||||||
State networkState = networkInfo.getState();
|
|
||||||
Log.i(TAG, "Network type: " + networkType + " state: " + networkState);
|
|
||||||
if (networkType == mNetworkType && networkInfo.getState() == mNetState) {
|
|
||||||
mReceiveLatch.countDown();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean waitForState() throws InterruptedException {
|
|
||||||
return mReceiveLatch.await(30, TimeUnit.SECONDS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback used in testRegisterNetworkCallback that allows caller to block on
|
|
||||||
* {@code onAvailable}.
|
|
||||||
*/
|
|
||||||
private static class TestNetworkCallback extends ConnectivityManager.NetworkCallback {
|
|
||||||
private final CountDownLatch mAvailableLatch = new CountDownLatch(1);
|
|
||||||
private final CountDownLatch mLostLatch = new CountDownLatch(1);
|
|
||||||
private final CountDownLatch mUnavailableLatch = new CountDownLatch(1);
|
|
||||||
|
|
||||||
public Network currentNetwork;
|
|
||||||
public Network lastLostNetwork;
|
|
||||||
|
|
||||||
public Network waitForAvailable() throws InterruptedException {
|
|
||||||
return mAvailableLatch.await(30, TimeUnit.SECONDS) ? currentNetwork : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Network waitForLost() throws InterruptedException {
|
|
||||||
return mLostLatch.await(30, TimeUnit.SECONDS) ? lastLostNetwork : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean waitForUnavailable() throws InterruptedException {
|
|
||||||
return mUnavailableLatch.await(2, TimeUnit.SECONDS);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAvailable(Network network) {
|
|
||||||
currentNetwork = network;
|
|
||||||
mAvailableLatch.countDown();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onLost(Network network) {
|
|
||||||
lastLostNetwork = network;
|
|
||||||
if (network.equals(currentNetwork)) {
|
|
||||||
currentNetwork = null;
|
|
||||||
}
|
|
||||||
mLostLatch.countDown();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onUnavailable() {
|
|
||||||
mUnavailableLatch.countDown();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Network getWifiNetwork() {
|
|
||||||
TestNetworkCallback callback = new TestNetworkCallback();
|
|
||||||
mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback);
|
|
||||||
Network network = null;
|
|
||||||
try {
|
|
||||||
network = callback.waitForAvailable();
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
fail("NetworkCallback wait was interrupted.");
|
|
||||||
} finally {
|
|
||||||
mCm.unregisterNetworkCallback(callback);
|
|
||||||
}
|
|
||||||
assertNotNull("Cannot find Network for wifi. Is wifi connected?", network);
|
|
||||||
return network;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Verify restricted networks cannot be requested. */
|
/** Verify restricted networks cannot be requested. */
|
||||||
@AppModeFull(reason = "CHANGE_NETWORK_STATE permission can't be granted to instant apps")
|
@AppModeFull(reason = "CHANGE_NETWORK_STATE permission can't be granted to instant apps")
|
||||||
public void testRestrictedNetworks() {
|
public void testRestrictedNetworks() {
|
||||||
@@ -1151,7 +890,7 @@ public class ConnectivityManagerTest extends AndroidTestCase {
|
|||||||
if (!isKeepaliveSupported()) return;
|
if (!isKeepaliveSupported()) return;
|
||||||
|
|
||||||
final Network network = ensureWifiConnected();
|
final Network network = ensureWifiConnected();
|
||||||
final byte[] requestBytes = HTTP_REQUEST.getBytes("UTF-8");
|
final byte[] requestBytes = CtsNetUtils.HTTP_REQUEST.getBytes("UTF-8");
|
||||||
// So far only ipv4 tcp keepalive offload is supported.
|
// So far only ipv4 tcp keepalive offload is supported.
|
||||||
// TODO: add test case for ipv6 tcp keepalive offload when it is supported.
|
// TODO: add test case for ipv6 tcp keepalive offload when it is supported.
|
||||||
try (Socket s = getConnectedSocket(network, TEST_HOST, HTTP_PORT,
|
try (Socket s = getConnectedSocket(network, TEST_HOST, HTTP_PORT,
|
||||||
|
|||||||
25
tests/cts/net/util/Android.bp
Normal file
25
tests/cts/net/util/Android.bp
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
//
|
||||||
|
// Copyright (C) 2019 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.
|
||||||
|
//
|
||||||
|
|
||||||
|
// Common utilities for cts net tests.
|
||||||
|
java_library {
|
||||||
|
name: "cts-net-utils",
|
||||||
|
srcs: ["java/**/*.java", "java/**/*.kt"],
|
||||||
|
static_libs: [
|
||||||
|
"compatibility-device-util-axt",
|
||||||
|
"junit",
|
||||||
|
],
|
||||||
|
}
|
||||||
353
tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java
Normal file
353
tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java
Normal file
@@ -0,0 +1,353 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 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.util;
|
||||||
|
|
||||||
|
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
|
||||||
|
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
|
import android.net.ConnectivityManager;
|
||||||
|
import android.net.ConnectivityManager.NetworkCallback;
|
||||||
|
import android.net.Network;
|
||||||
|
import android.net.NetworkCapabilities;
|
||||||
|
import android.net.NetworkInfo;
|
||||||
|
import android.net.NetworkInfo.State;
|
||||||
|
import android.net.NetworkRequest;
|
||||||
|
import android.net.wifi.WifiManager;
|
||||||
|
import android.system.Os;
|
||||||
|
import android.system.OsConstants;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.android.compatibility.common.util.SystemUtil;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
public final class CtsNetUtils {
|
||||||
|
private static final String TAG = CtsNetUtils.class.getSimpleName();
|
||||||
|
private static final int DURATION = 10000;
|
||||||
|
private static final int SOCKET_TIMEOUT_MS = 2000;
|
||||||
|
|
||||||
|
public static final int HTTP_PORT = 80;
|
||||||
|
public static final String TEST_HOST = "connectivitycheck.gstatic.com";
|
||||||
|
public static final String HTTP_REQUEST =
|
||||||
|
"GET /generate_204 HTTP/1.0\r\n" +
|
||||||
|
"Host: " + TEST_HOST + "\r\n" +
|
||||||
|
"Connection: keep-alive\r\n\r\n";
|
||||||
|
// Action sent to ConnectivityActionReceiver when a network callback is sent via PendingIntent.
|
||||||
|
public static final String NETWORK_CALLBACK_ACTION =
|
||||||
|
"ConnectivityManagerTest.NetworkCallbackAction";
|
||||||
|
|
||||||
|
private Context mContext;
|
||||||
|
private ConnectivityManager mCm;
|
||||||
|
private WifiManager mWifiManager;
|
||||||
|
private TestNetworkCallback mCellNetworkCallback;
|
||||||
|
|
||||||
|
public CtsNetUtils(Context context) {
|
||||||
|
mContext = context;
|
||||||
|
mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||||
|
mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toggle WiFi twice, leaving it in the state it started in
|
||||||
|
public void toggleWifi() {
|
||||||
|
if (mWifiManager.isWifiEnabled()) {
|
||||||
|
Network wifiNetwork = getWifiNetwork();
|
||||||
|
disconnectFromWifi(wifiNetwork);
|
||||||
|
connectToWifi();
|
||||||
|
} else {
|
||||||
|
connectToWifi();
|
||||||
|
Network wifiNetwork = getWifiNetwork();
|
||||||
|
disconnectFromWifi(wifiNetwork);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Enable WiFi and wait for it to become connected to a network. */
|
||||||
|
public Network connectToWifi() {
|
||||||
|
final TestNetworkCallback callback = new TestNetworkCallback();
|
||||||
|
mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback);
|
||||||
|
Network wifiNetwork = null;
|
||||||
|
|
||||||
|
ConnectivityActionReceiver receiver = new ConnectivityActionReceiver(
|
||||||
|
mCm, ConnectivityManager.TYPE_WIFI, NetworkInfo.State.CONNECTED);
|
||||||
|
IntentFilter filter = new IntentFilter();
|
||||||
|
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
|
||||||
|
mContext.registerReceiver(receiver, filter);
|
||||||
|
|
||||||
|
boolean connected = false;
|
||||||
|
try {
|
||||||
|
SystemUtil.runShellCommand("svc wifi enable");
|
||||||
|
// Ensure we get both an onAvailable callback and a CONNECTIVITY_ACTION.
|
||||||
|
wifiNetwork = callback.waitForAvailable();
|
||||||
|
assertNotNull(wifiNetwork);
|
||||||
|
connected = receiver.waitForState();
|
||||||
|
} catch (InterruptedException ex) {
|
||||||
|
fail("connectToWifi was interrupted");
|
||||||
|
} finally {
|
||||||
|
mCm.unregisterNetworkCallback(callback);
|
||||||
|
mContext.unregisterReceiver(receiver);
|
||||||
|
}
|
||||||
|
|
||||||
|
assertTrue("Wifi must be configured to connect to an access point for this test.",
|
||||||
|
connected);
|
||||||
|
return wifiNetwork;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Disable WiFi and wait for it to become disconnected from the network. */
|
||||||
|
public void disconnectFromWifi(Network wifiNetworkToCheck) {
|
||||||
|
final TestNetworkCallback callback = new TestNetworkCallback();
|
||||||
|
mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback);
|
||||||
|
Network lostWifiNetwork = null;
|
||||||
|
|
||||||
|
ConnectivityActionReceiver receiver = new ConnectivityActionReceiver(
|
||||||
|
mCm, ConnectivityManager.TYPE_WIFI, NetworkInfo.State.DISCONNECTED);
|
||||||
|
IntentFilter filter = new IntentFilter();
|
||||||
|
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
|
||||||
|
mContext.registerReceiver(receiver, filter);
|
||||||
|
|
||||||
|
// Assert that we can establish a TCP connection on wifi.
|
||||||
|
Socket wifiBoundSocket = null;
|
||||||
|
if (wifiNetworkToCheck != null) {
|
||||||
|
try {
|
||||||
|
wifiBoundSocket = getBoundSocket(wifiNetworkToCheck, TEST_HOST, HTTP_PORT);
|
||||||
|
testHttpRequest(wifiBoundSocket);
|
||||||
|
} catch (IOException e) {
|
||||||
|
fail("HTTP request before wifi disconnected failed with: " + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean disconnected = false;
|
||||||
|
try {
|
||||||
|
SystemUtil.runShellCommand("svc wifi disable");
|
||||||
|
// Ensure we get both an onLost callback and a CONNECTIVITY_ACTION.
|
||||||
|
lostWifiNetwork = callback.waitForLost();
|
||||||
|
assertNotNull(lostWifiNetwork);
|
||||||
|
disconnected = receiver.waitForState();
|
||||||
|
} catch (InterruptedException ex) {
|
||||||
|
fail("disconnectFromWifi was interrupted");
|
||||||
|
} finally {
|
||||||
|
mCm.unregisterNetworkCallback(callback);
|
||||||
|
mContext.unregisterReceiver(receiver);
|
||||||
|
}
|
||||||
|
|
||||||
|
assertTrue("Wifi failed to reach DISCONNECTED state.", disconnected);
|
||||||
|
|
||||||
|
// Check that the socket is closed when wifi disconnects.
|
||||||
|
if (wifiBoundSocket != null) {
|
||||||
|
try {
|
||||||
|
testHttpRequest(wifiBoundSocket);
|
||||||
|
fail("HTTP request should not succeed after wifi disconnects");
|
||||||
|
} catch (IOException expected) {
|
||||||
|
assertEquals(Os.strerror(OsConstants.ECONNABORTED), expected.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Network getWifiNetwork() {
|
||||||
|
TestNetworkCallback callback = new TestNetworkCallback();
|
||||||
|
mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback);
|
||||||
|
Network network = null;
|
||||||
|
try {
|
||||||
|
network = callback.waitForAvailable();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
fail("NetworkCallback wait was interrupted.");
|
||||||
|
} finally {
|
||||||
|
mCm.unregisterNetworkCallback(callback);
|
||||||
|
}
|
||||||
|
assertNotNull("Cannot find Network for wifi. Is wifi connected?", network);
|
||||||
|
return network;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Network connectToCell() throws InterruptedException {
|
||||||
|
if (cellConnectAttempted()) {
|
||||||
|
throw new IllegalStateException("Already connected");
|
||||||
|
}
|
||||||
|
NetworkRequest cellRequest = new NetworkRequest.Builder()
|
||||||
|
.addTransportType(TRANSPORT_CELLULAR)
|
||||||
|
.addCapability(NET_CAPABILITY_INTERNET)
|
||||||
|
.build();
|
||||||
|
mCellNetworkCallback = new TestNetworkCallback();
|
||||||
|
mCm.requestNetwork(cellRequest, mCellNetworkCallback);
|
||||||
|
final Network cellNetwork = mCellNetworkCallback.waitForAvailable();
|
||||||
|
assertNotNull("Cell network not available. " +
|
||||||
|
"Please ensure the device has working mobile data.", cellNetwork);
|
||||||
|
return cellNetwork;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void disconnectFromCell() {
|
||||||
|
if (!cellConnectAttempted()) {
|
||||||
|
throw new IllegalStateException("Cell connection not attempted");
|
||||||
|
}
|
||||||
|
mCm.unregisterNetworkCallback(mCellNetworkCallback);
|
||||||
|
mCellNetworkCallback = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean cellConnectAttempted() {
|
||||||
|
return mCellNetworkCallback != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private NetworkRequest makeWifiNetworkRequest() {
|
||||||
|
return new NetworkRequest.Builder()
|
||||||
|
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testHttpRequest(Socket s) throws IOException {
|
||||||
|
OutputStream out = s.getOutputStream();
|
||||||
|
InputStream in = s.getInputStream();
|
||||||
|
|
||||||
|
final byte[] requestBytes = HTTP_REQUEST.getBytes("UTF-8");
|
||||||
|
byte[] responseBytes = new byte[4096];
|
||||||
|
out.write(requestBytes);
|
||||||
|
in.read(responseBytes);
|
||||||
|
assertTrue(new String(responseBytes, "UTF-8").startsWith("HTTP/1.0 204 No Content\r\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Socket getBoundSocket(Network network, String host, int port) throws IOException {
|
||||||
|
InetSocketAddress addr = new InetSocketAddress(host, port);
|
||||||
|
Socket s = network.getSocketFactory().createSocket();
|
||||||
|
try {
|
||||||
|
s.setSoTimeout(SOCKET_TIMEOUT_MS);
|
||||||
|
s.connect(addr, SOCKET_TIMEOUT_MS);
|
||||||
|
} catch (IOException e) {
|
||||||
|
s.close();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Receiver that captures the last connectivity change's network type and state. Recognizes
|
||||||
|
* both {@code CONNECTIVITY_ACTION} and {@code NETWORK_CALLBACK_ACTION} intents.
|
||||||
|
*/
|
||||||
|
public static class ConnectivityActionReceiver extends BroadcastReceiver {
|
||||||
|
|
||||||
|
private final CountDownLatch mReceiveLatch = new CountDownLatch(1);
|
||||||
|
|
||||||
|
private final int mNetworkType;
|
||||||
|
private final NetworkInfo.State mNetState;
|
||||||
|
private final ConnectivityManager mCm;
|
||||||
|
|
||||||
|
public ConnectivityActionReceiver(ConnectivityManager cm, int networkType,
|
||||||
|
NetworkInfo.State netState) {
|
||||||
|
this.mCm = cm;
|
||||||
|
mNetworkType = networkType;
|
||||||
|
mNetState = netState;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
String action = intent.getAction();
|
||||||
|
NetworkInfo networkInfo = null;
|
||||||
|
|
||||||
|
// When receiving ConnectivityManager.CONNECTIVITY_ACTION, the NetworkInfo parcelable
|
||||||
|
// is stored in EXTRA_NETWORK_INFO. With a NETWORK_CALLBACK_ACTION, the Network is
|
||||||
|
// sent in EXTRA_NETWORK and we need to ask the ConnectivityManager for the NetworkInfo.
|
||||||
|
if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) {
|
||||||
|
networkInfo = intent.getExtras()
|
||||||
|
.getParcelable(ConnectivityManager.EXTRA_NETWORK_INFO);
|
||||||
|
assertNotNull("ConnectivityActionReceiver expected EXTRA_NETWORK_INFO",
|
||||||
|
networkInfo);
|
||||||
|
} else if (NETWORK_CALLBACK_ACTION.equals(action)) {
|
||||||
|
Network network = intent.getExtras()
|
||||||
|
.getParcelable(ConnectivityManager.EXTRA_NETWORK);
|
||||||
|
assertNotNull("ConnectivityActionReceiver expected EXTRA_NETWORK", network);
|
||||||
|
networkInfo = this.mCm.getNetworkInfo(network);
|
||||||
|
if (networkInfo == null) {
|
||||||
|
// When disconnecting, it seems like we get an intent sent with an invalid
|
||||||
|
// Network; that is, by the time we call ConnectivityManager.getNetworkInfo(),
|
||||||
|
// it is invalid. Ignore these.
|
||||||
|
Log.i(TAG, "ConnectivityActionReceiver NETWORK_CALLBACK_ACTION ignoring "
|
||||||
|
+ "invalid network");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fail("ConnectivityActionReceiver received unxpected intent action: " + action);
|
||||||
|
}
|
||||||
|
|
||||||
|
assertNotNull("ConnectivityActionReceiver didn't find NetworkInfo", networkInfo);
|
||||||
|
int networkType = networkInfo.getType();
|
||||||
|
State networkState = networkInfo.getState();
|
||||||
|
Log.i(TAG, "Network type: " + networkType + " state: " + networkState);
|
||||||
|
if (networkType == mNetworkType && networkInfo.getState() == mNetState) {
|
||||||
|
mReceiveLatch.countDown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean waitForState() throws InterruptedException {
|
||||||
|
return mReceiveLatch.await(30, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback used in testRegisterNetworkCallback that allows caller to block on
|
||||||
|
* {@code onAvailable}.
|
||||||
|
*/
|
||||||
|
public static class TestNetworkCallback extends ConnectivityManager.NetworkCallback {
|
||||||
|
private final CountDownLatch mAvailableLatch = new CountDownLatch(1);
|
||||||
|
private final CountDownLatch mLostLatch = new CountDownLatch(1);
|
||||||
|
private final CountDownLatch mUnavailableLatch = new CountDownLatch(1);
|
||||||
|
|
||||||
|
public Network currentNetwork;
|
||||||
|
public Network lastLostNetwork;
|
||||||
|
|
||||||
|
public Network waitForAvailable() throws InterruptedException {
|
||||||
|
return mAvailableLatch.await(30, TimeUnit.SECONDS) ? currentNetwork : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Network waitForLost() throws InterruptedException {
|
||||||
|
return mLostLatch.await(30, TimeUnit.SECONDS) ? lastLostNetwork : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean waitForUnavailable() throws InterruptedException {
|
||||||
|
return mUnavailableLatch.await(2, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAvailable(Network network) {
|
||||||
|
currentNetwork = network;
|
||||||
|
mAvailableLatch.countDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLost(Network network) {
|
||||||
|
lastLostNetwork = network;
|
||||||
|
if (network.equals(currentNetwork)) {
|
||||||
|
currentNetwork = null;
|
||||||
|
}
|
||||||
|
mLostLatch.countDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onUnavailable() {
|
||||||
|
mUnavailableLatch.countDown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user