Merge changes from topic "conn-diags-skipped"
* changes:
Update ConnDiags CTS test to expect validation result SKIPPED.
Report result SKIPPED in ConnDiags if the network is not validated.
diff --git a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
index 56dc69c..2c1fd29 100644
--- a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
+++ b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
@@ -1069,10 +1069,11 @@
throw new AssertionError("IP address array not valid IPv4 address!");
}
+ final String protoStr = (key.l4proto == OsConstants.IPPROTO_TCP) ? "tcp" : "udp";
final String ageStr = (value.lastUsed == 0) ? "-"
: String.format("%dms", (now - value.lastUsed) / 1_000_000);
- return String.format("[%s] %d(%s) %s:%d -> %d(%s) %s:%d -> %s:%d [%s] %s",
- key.dstMac, key.iif, getIfName(key.iif), src4, key.srcPort,
+ return String.format("%s [%s] %d(%s) %s:%d -> %d(%s) %s:%d -> %s:%d [%s] %s",
+ protoStr, key.dstMac, key.iif, getIfName(key.iif), src4, key.srcPort,
value.oif, getIfName(value.oif),
public4, publicPort, dst4, value.dstPort, value.ethDstMac, ageStr);
}
@@ -1095,12 +1096,14 @@
try (BpfMap<Tether4Key, Tether4Value> upstreamMap = mDeps.getBpfUpstream4Map();
BpfMap<Tether4Key, Tether4Value> downstreamMap = mDeps.getBpfDownstream4Map()) {
- pw.println("IPv4 Upstream: [inDstMac] iif(iface) src -> nat -> dst [outDstMac] age");
+ pw.println("IPv4 Upstream: proto [inDstMac] iif(iface) src -> nat -> "
+ + "dst [outDstMac] age");
pw.increaseIndent();
dumpIpv4ForwardingRuleMap(now, UPSTREAM, upstreamMap, pw);
pw.decreaseIndent();
- pw.println("IPv4 Downstream: [inDstMac] iif(iface) src -> nat -> dst [outDstMac] age");
+ pw.println("IPv4 Downstream: proto [inDstMac] iif(iface) src -> nat -> "
+ + "dst [outDstMac] age");
pw.increaseIndent();
dumpIpv4ForwardingRuleMap(now, DOWNSTREAM, downstreamMap, pw);
pw.decreaseIndent();
diff --git a/Tethering/tests/Android.bp b/Tethering/tests/Android.bp
index 8f31c57..72ca666 100644
--- a/Tethering/tests/Android.bp
+++ b/Tethering/tests/Android.bp
@@ -22,7 +22,7 @@
name: "TetheringTestsJarJarRules",
srcs: ["jarjar-rules.txt"],
visibility: [
- "//frameworks/base/packages/Tethering/tests:__subpackages__",
+ "//packages/modules/Connectivity/tests:__subpackages__",
"//packages/modules/Connectivity/Tethering/tests:__subpackages__",
]
}
diff --git a/Tethering/tests/integration/Android.bp b/Tethering/tests/integration/Android.bp
index e807613..b93a969 100644
--- a/Tethering/tests/integration/Android.bp
+++ b/Tethering/tests/integration/Android.bp
@@ -78,9 +78,27 @@
compile_multilib: "both",
}
+android_library {
+ name: "TetheringCoverageTestsLib",
+ min_sdk_version: "30",
+ static_libs: [
+ "NetdStaticLibTestsLib",
+ "NetworkStaticLibTestsLib",
+ "NetworkStackTestsLib",
+ "TetheringTestsLatestSdkLib",
+ "TetheringIntegrationTestsLatestSdkLib",
+ ],
+ jarjar_rules: ":TetheringTestsJarJarRules",
+ manifest: "AndroidManifest_coverage.xml",
+ visibility: [
+ "//packages/modules/Connectivity/tests:__subpackages__"
+ ],
+}
+
// Special version of the tethering tests that includes all tests necessary for code coverage
// purposes. This is currently the union of TetheringTests, TetheringIntegrationTests and
// NetworkStackTests.
+// TODO: remove in favor of ConnectivityCoverageTests, which includes below tests and more
android_test {
name: "TetheringCoverageTests",
platform_apis: true,
@@ -91,11 +109,7 @@
defaults: ["libnetworkstackutilsjni_deps"],
static_libs: [
"modules-utils-native-coverage-listener",
- "NetdStaticLibTestsLib",
- "NetworkStaticLibTestsLib",
- "NetworkStackTestsLib",
- "TetheringTestsLatestSdkLib",
- "TetheringIntegrationTestsLatestSdkLib",
+ "TetheringCoverageTestsLib",
],
jni_libs: [
// For mockito extended
diff --git a/Tethering/tests/unit/Android.bp b/Tethering/tests/unit/Android.bp
index 192a540..f6e29cd 100644
--- a/Tethering/tests/unit/Android.bp
+++ b/Tethering/tests/unit/Android.bp
@@ -75,7 +75,6 @@
"libstaticjvmtiagent",
"libtetherutilsjni",
],
- jarjar_rules: ":TetheringTestsJarJarRules",
}
// Library containing the unit tests. This is used by the coverage test target to pull in the
@@ -100,4 +99,5 @@
],
defaults: ["TetheringTestsDefaults"],
compile_multilib: "both",
+ jarjar_rules: ":TetheringTestsJarJarRules",
}
diff --git a/framework/Android.bp b/framework/Android.bp
index 93ef3bf..ee3a5d5 100644
--- a/framework/Android.bp
+++ b/framework/Android.bp
@@ -97,8 +97,6 @@
],
},
impl_only_libs: [
- // TODO (b/183097033) remove once module_current includes core_platform
- "stable.core.platform.api.stubs",
"framework-tethering.stubs.module_lib",
"framework-wifi.stubs.module_lib",
"net-utils-device-common",
diff --git a/framework/src/android/net/ConnectivityManager.java b/framework/src/android/net/ConnectivityManager.java
index 7e2f688..14ec608 100644
--- a/framework/src/android/net/ConnectivityManager.java
+++ b/framework/src/android/net/ConnectivityManager.java
@@ -4939,7 +4939,7 @@
Log.e(TAG, "Can't set proxy properties", e);
}
// Must flush DNS cache as new network may have different DNS resolutions.
- InetAddressCompat.clearDnsCache();
+ InetAddress.clearDnsCache();
// Must flush socket pool as idle sockets will be bound to previous network and may
// cause subsequent fetches to be performed on old network.
NetworkEventDispatcher.getInstance().dispatchNetworkConfigurationChange();
diff --git a/framework/src/android/net/InetAddressCompat.java b/framework/src/android/net/InetAddressCompat.java
deleted file mode 100644
index 6b7e75c..0000000
--- a/framework/src/android/net/InetAddressCompat.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2021 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;
-
-import android.util.Log;
-
-import java.lang.reflect.InvocationTargetException;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-
-/**
- * Compatibility utility for InetAddress core platform APIs.
- *
- * Connectivity has access to such APIs, but they are not part of the module_current stubs yet
- * (only core_current). Most stable core platform APIs are included manually in the connectivity
- * build rules, but because InetAddress is also part of the base java SDK that is earlier on the
- * classpath, the extra core platform APIs are not seen.
- *
- * TODO (b/183097033): remove this utility as soon as core_current is part of module_current
- * @hide
- */
-public class InetAddressCompat {
-
- /**
- * @see InetAddress#clearDnsCache()
- */
- public static void clearDnsCache() {
- try {
- InetAddress.class.getMethod("clearDnsCache").invoke(null);
- } catch (InvocationTargetException e) {
- if (e.getCause() instanceof RuntimeException) {
- throw (RuntimeException) e.getCause();
- }
- throw new IllegalStateException("Unknown InvocationTargetException", e.getCause());
- } catch (IllegalAccessException | NoSuchMethodException e) {
- Log.wtf(InetAddressCompat.class.getSimpleName(), "Error clearing DNS cache", e);
- }
- }
-
- /**
- * @see InetAddress#getAllByNameOnNet(String, int)
- */
- public static InetAddress[] getAllByNameOnNet(String host, int netId) throws
- UnknownHostException {
- return (InetAddress[]) callGetByNameMethod("getAllByNameOnNet", host, netId);
- }
-
- /**
- * @see InetAddress#getByNameOnNet(String, int)
- */
- public static InetAddress getByNameOnNet(String host, int netId) throws
- UnknownHostException {
- return (InetAddress) callGetByNameMethod("getByNameOnNet", host, netId);
- }
-
- private static Object callGetByNameMethod(String method, String host, int netId)
- throws UnknownHostException {
- try {
- return InetAddress.class.getMethod(method, String.class, int.class)
- .invoke(null, host, netId);
- } catch (InvocationTargetException e) {
- if (e.getCause() instanceof UnknownHostException) {
- throw (UnknownHostException) e.getCause();
- }
- if (e.getCause() instanceof RuntimeException) {
- throw (RuntimeException) e.getCause();
- }
- throw new IllegalStateException("Unknown InvocationTargetException", e.getCause());
- } catch (IllegalAccessException | NoSuchMethodException e) {
- Log.wtf(InetAddressCompat.class.getSimpleName(), "Error calling " + method, e);
- throw new IllegalStateException("Error querying via " + method, e);
- }
- }
-}
diff --git a/framework/src/android/net/Network.java b/framework/src/android/net/Network.java
index 1f49033..b3770ea 100644
--- a/framework/src/android/net/Network.java
+++ b/framework/src/android/net/Network.java
@@ -142,7 +142,7 @@
* @throws UnknownHostException if the address lookup fails.
*/
public InetAddress[] getAllByName(String host) throws UnknownHostException {
- return InetAddressCompat.getAllByNameOnNet(host, getNetIdForResolv());
+ return InetAddress.getAllByNameOnNet(host, getNetIdForResolv());
}
/**
@@ -155,7 +155,7 @@
* if the address lookup fails.
*/
public InetAddress getByName(String host) throws UnknownHostException {
- return InetAddressCompat.getByNameOnNet(host, getNetIdForResolv());
+ return InetAddress.getByNameOnNet(host, getNetIdForResolv());
}
/**
diff --git a/service/Android.bp b/service/Android.bp
index 841e189..848de12 100644
--- a/service/Android.bp
+++ b/service/Android.bp
@@ -57,9 +57,6 @@
":net-module-utils-srcs",
],
libs: [
- // TODO (b/183097033) remove once system_server_current includes core_current
- "stable.core.platform.api.stubs",
- "android_system_server_stubs_current",
"framework-annotations-lib",
"framework-connectivity.impl",
"framework-tethering.stubs.module_lib",
@@ -112,3 +109,9 @@
"com.android.tethering",
],
}
+
+filegroup {
+ name: "connectivity-jarjar-rules",
+ srcs: ["jarjar-rules.txt"],
+ visibility: ["//packages/modules/Connectivity:__subpackages__"],
+}
diff --git a/service/ServiceConnectivityResources/res/values/config.xml b/service/ServiceConnectivityResources/res/values/config.xml
index 70ddb9a..bf32ad5 100644
--- a/service/ServiceConnectivityResources/res/values/config.xml
+++ b/service/ServiceConnectivityResources/res/values/config.xml
@@ -111,4 +111,7 @@
notification that can be dismissed. -->
<bool name="config_ongoingSignInNotification">false</bool>
+ <!-- Whether to cancel network notifications automatically when tapped -->
+ <bool name="config_autoCancelNetworkNotifications">true</bool>
+
</resources>
diff --git a/service/ServiceConnectivityResources/res/values/overlayable.xml b/service/ServiceConnectivityResources/res/values/overlayable.xml
index fd23566..6ac6a0e 100644
--- a/service/ServiceConnectivityResources/res/values/overlayable.xml
+++ b/service/ServiceConnectivityResources/res/values/overlayable.xml
@@ -31,7 +31,9 @@
<item type="integer" name="config_networkNotifySwitchType"/>
<item type="array" name="config_networkNotifySwitches"/>
<item type="bool" name="config_ongoingSignInNotification"/>
-
+ <item type="bool" name="config_autoCancelNetworkNotifications"/>
+ <item type="drawable" name="stat_notify_wifi_in_range"/>
+ <item type="drawable" name="stat_notify_rssi_in_range"/>
</policy>
</overlayable>
</resources>
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index 0c4b6aa..1a9ff25 100644
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -6307,7 +6307,8 @@
callingAttributionTag);
if (VDBG) log("pendingListenForNetwork for " + nri);
- mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_LISTENER, nri));
+ mHandler.sendMessage(mHandler.obtainMessage(
+ EVENT_REGISTER_NETWORK_LISTENER_WITH_INTENT, nri));
}
/** Returns the next Network provider ID. */
@@ -10044,7 +10045,7 @@
// - The request for the mobile network preferred.
// - The request for the default network, for fallback.
requests.add(createDefaultInternetRequestForTransport(
- TRANSPORT_CELLULAR, NetworkRequest.Type.LISTEN));
+ TRANSPORT_CELLULAR, NetworkRequest.Type.REQUEST));
requests.add(createDefaultInternetRequestForTransport(
TYPE_NONE, NetworkRequest.Type.TRACK_DEFAULT));
final Set<UidRange> ranges = new ArraySet<>();
diff --git a/service/src/com/android/server/connectivity/KeepaliveTracker.java b/service/src/com/android/server/connectivity/KeepaliveTracker.java
index acf39f0..ee1538a 100644
--- a/service/src/com/android/server/connectivity/KeepaliveTracker.java
+++ b/service/src/com/android/server/connectivity/KeepaliveTracker.java
@@ -373,12 +373,10 @@
Log.e(TAG, "Cannot stop unowned keepalive " + mSlot + " on " + mNai.network);
}
}
- // Ignore the case when the network disconnects immediately after stop() has been
- // called and the keepalive code is waiting for the response from the modem. This
- // might happen when the caller listens for a lower-layer network disconnect
- // callback and stop the keepalive at that time. But the stop() races with the
- // stop() generated in ConnectivityService network disconnection code path.
- if (mStartedState == STOPPING && reason == ERROR_INVALID_NETWORK) return;
+ // To prevent races from re-entrance of stop(), return if the state is already stopping.
+ // This might happen if multiple event sources stop keepalive in a short time. Such as
+ // network disconnect after user calls stop(), or tear down socket after binder died.
+ if (mStartedState == STOPPING) return;
// Store the reason of stopping, and report it after the keepalive is fully stopped.
if (mStopReason != ERROR_STOP_REASON_UNINITIALIZED) {
diff --git a/service/src/com/android/server/connectivity/NetworkNotificationManager.java b/service/src/com/android/server/connectivity/NetworkNotificationManager.java
index 3dc79c5..ae98d92 100644
--- a/service/src/com/android/server/connectivity/NetworkNotificationManager.java
+++ b/service/src/com/android/server/connectivity/NetworkNotificationManager.java
@@ -274,7 +274,7 @@
.setWhen(System.currentTimeMillis())
.setShowWhen(notifyType == NotificationType.NETWORK_SWITCH)
.setSmallIcon(icon)
- .setAutoCancel(true)
+ .setAutoCancel(r.getBoolean(R.bool.config_autoCancelNetworkNotifications))
.setTicker(title)
.setColor(mContext.getColor(android.R.color.system_notification_accent_color))
.setContentTitle(title)
diff --git a/service/src/com/android/server/connectivity/OsCompat.java b/service/src/com/android/server/connectivity/OsCompat.java
deleted file mode 100644
index 57e3dcd..0000000
--- a/service/src/com/android/server/connectivity/OsCompat.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.connectivity;
-
-import android.system.ErrnoException;
-import android.system.Os;
-
-import java.io.FileDescriptor;
-
-/**
- * Compatibility utility for android.system.Os core platform APIs.
- *
- * Connectivity has access to such APIs, but they are not part of the module_current stubs yet
- * (only core_current). Most stable core platform APIs are included manually in the connectivity
- * build rules, but because Os is also part of the base java SDK that is earlier on the
- * classpath, the extra core platform APIs are not seen.
- *
- * TODO (b/157639992, b/183097033): remove as soon as core_current is part of system_server_current
- * @hide
- */
-public class OsCompat {
- // This value should be correct on all architectures supported by Android, but hardcoding ioctl
- // numbers should be avoided.
- /**
- * @see android.system.OsConstants#TIOCOUTQ
- */
- public static final int TIOCOUTQ = 0x5411;
-
- /**
- * @see android.system.Os#getsockoptInt(FileDescriptor, int, int)
- */
- public static int getsockoptInt(FileDescriptor fd, int level, int option) throws
- ErrnoException {
- try {
- return (int) Os.class.getMethod(
- "getsockoptInt", FileDescriptor.class, int.class, int.class)
- .invoke(null, fd, level, option);
- } catch (ReflectiveOperationException e) {
- if (e.getCause() instanceof ErrnoException) {
- throw (ErrnoException) e.getCause();
- }
- throw new IllegalStateException("Error calling getsockoptInt", e);
- }
- }
-
- /**
- * @see android.system.Os#ioctlInt(FileDescriptor, int)
- */
- public static int ioctlInt(FileDescriptor fd, int cmd) throws
- ErrnoException {
- try {
- return (int) Os.class.getMethod(
- "ioctlInt", FileDescriptor.class, int.class).invoke(null, fd, cmd);
- } catch (ReflectiveOperationException e) {
- if (e.getCause() instanceof ErrnoException) {
- throw (ErrnoException) e.getCause();
- }
- throw new IllegalStateException("Error calling ioctlInt", e);
- }
- }
-}
diff --git a/service/src/com/android/server/connectivity/TcpKeepaliveController.java b/service/src/com/android/server/connectivity/TcpKeepaliveController.java
index 73f3475..c480594 100644
--- a/service/src/com/android/server/connectivity/TcpKeepaliveController.java
+++ b/service/src/com/android/server/connectivity/TcpKeepaliveController.java
@@ -27,8 +27,7 @@
import static android.system.OsConstants.IPPROTO_TCP;
import static android.system.OsConstants.IP_TOS;
import static android.system.OsConstants.IP_TTL;
-
-import static com.android.server.connectivity.OsCompat.TIOCOUTQ;
+import static android.system.OsConstants.TIOCOUTQ;
import android.annotation.NonNull;
import android.net.InvalidPacketException;
@@ -176,10 +175,10 @@
}
// Query write sequence number from SEND_QUEUE.
Os.setsockoptInt(fd, IPPROTO_TCP, TCP_REPAIR_QUEUE, TCP_SEND_QUEUE);
- tcpDetails.seq = OsCompat.getsockoptInt(fd, IPPROTO_TCP, TCP_QUEUE_SEQ);
+ tcpDetails.seq = Os.getsockoptInt(fd, IPPROTO_TCP, TCP_QUEUE_SEQ);
// Query read sequence number from RECV_QUEUE.
Os.setsockoptInt(fd, IPPROTO_TCP, TCP_REPAIR_QUEUE, TCP_RECV_QUEUE);
- tcpDetails.ack = OsCompat.getsockoptInt(fd, IPPROTO_TCP, TCP_QUEUE_SEQ);
+ tcpDetails.ack = Os.getsockoptInt(fd, IPPROTO_TCP, TCP_QUEUE_SEQ);
// Switch to NO_QUEUE to prevent illegal socket read/write in repair mode.
Os.setsockoptInt(fd, IPPROTO_TCP, TCP_REPAIR_QUEUE, TCP_NO_QUEUE);
// Finally, check if socket is still idle. TODO : this check needs to move to
@@ -199,9 +198,9 @@
tcpDetails.rcvWndScale = trw.rcvWndScale;
if (tcpDetails.srcAddress.length == 4 /* V4 address length */) {
// Query TOS.
- tcpDetails.tos = OsCompat.getsockoptInt(fd, IPPROTO_IP, IP_TOS);
+ tcpDetails.tos = Os.getsockoptInt(fd, IPPROTO_IP, IP_TOS);
// Query TTL.
- tcpDetails.ttl = OsCompat.getsockoptInt(fd, IPPROTO_IP, IP_TTL);
+ tcpDetails.ttl = Os.getsockoptInt(fd, IPPROTO_IP, IP_TTL);
}
} catch (ErrnoException e) {
Log.e(TAG, "Exception reading TCP state from socket", e);
@@ -306,7 +305,7 @@
private static boolean isReceiveQueueEmpty(FileDescriptor fd)
throws ErrnoException {
- final int result = OsCompat.ioctlInt(fd, SIOCINQ);
+ final int result = Os.ioctlInt(fd, SIOCINQ);
if (result != 0) {
Log.e(TAG, "Read queue has data");
return false;
@@ -316,7 +315,7 @@
private static boolean isSendQueueEmpty(FileDescriptor fd)
throws ErrnoException {
- final int result = OsCompat.ioctlInt(fd, SIOCOUTQ);
+ final int result = Os.ioctlInt(fd, SIOCOUTQ);
if (result != 0) {
Log.e(TAG, "Write queue has data");
return false;
diff --git a/tests/common/Android.bp b/tests/common/Android.bp
index 8be8ea1..e1fab09 100644
--- a/tests/common/Android.bp
+++ b/tests/common/Android.bp
@@ -43,6 +43,23 @@
],
}
+// Connectivity coverage tests combines Tethering and Connectivity tests, each with their
+// respective jarjar rules applied.
+// Some tests may be duplicated (in particular static lib tests), as they need to be run under both
+// jarjared packages to cover both usages.
+android_library {
+ name: "ConnectivityCoverageTestsLib",
+ min_sdk_version: "30",
+ static_libs: [
+ "FrameworksNetTestsLib",
+ "NetdStaticLibTestsLib",
+ "NetworkStaticLibTestsLib",
+ ],
+ jarjar_rules: ":connectivity-jarjar-rules",
+ manifest: "AndroidManifest_coverage.xml",
+ visibility: ["//visibility:private"],
+}
+
android_test {
name: "ConnectivityCoverageTests",
// Tethering started on SDK 30
@@ -62,13 +79,9 @@
// (some tests would fail).
// TODO: consider removing extended mockito usage in tests that use it, for performance
"mockito-target-extended-minus-junit4",
- "FrameworksNetTestsLib",
"modules-utils-native-coverage-listener",
- "NetdStaticLibTestsLib",
- "NetworkStaticLibTestsLib",
- "NetworkStackTestsLib",
- "TetheringTestsLatestSdkLib",
- "TetheringIntegrationTestsLatestSdkLib",
+ "ConnectivityCoverageTestsLib",
+ "TetheringCoverageTestsLib",
],
jni_libs: [
// For mockito extended
diff --git a/tests/common/java/android/net/metrics/IpConnectivityLogTest.java b/tests/common/java/android/net/metrics/IpConnectivityLogTest.java
index d4780d3..ab97f2d 100644
--- a/tests/common/java/android/net/metrics/IpConnectivityLogTest.java
+++ b/tests/common/java/android/net/metrics/IpConnectivityLogTest.java
@@ -19,6 +19,8 @@
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static com.android.net.module.util.NetworkCapabilitiesUtils.unpackBits;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.timeout;
@@ -31,8 +33,6 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
-import com.android.internal.util.BitUtils;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -49,7 +49,7 @@
@SmallTest
public class IpConnectivityLogTest {
private static final int FAKE_NET_ID = 100;
- private static final int[] FAKE_TRANSPORT_TYPES = BitUtils.unpackBits(TRANSPORT_WIFI);
+ private static final int[] FAKE_TRANSPORT_TYPES = unpackBits(TRANSPORT_WIFI);
private static final long FAKE_TIME_STAMP = System.currentTimeMillis();
private static final String FAKE_INTERFACE_NAME = "test";
private static final IpReachabilityEvent FAKE_EV =
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyManagerTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyManagerTest.java
index ddc5fd4..ad7ec9e 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyManagerTest.java
+++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyManagerTest.java
@@ -23,6 +23,8 @@
import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isUidNetworkingBlocked;
import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isUidRestrictedOnMeteredNetworks;
import static com.android.cts.net.hostside.NetworkPolicyTestUtils.setRestrictBackground;
+import static com.android.cts.net.hostside.Property.BATTERY_SAVER_MODE;
+import static com.android.cts.net.hostside.Property.DATA_SAVER_MODE;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -79,6 +81,7 @@
assertFalse(isUidNetworkingBlocked(mUid, NON_METERED)); // Match NTWK_ALLOWED_NON_METERED
}
+ @RequiredProperties({DATA_SAVER_MODE, BATTERY_SAVER_MODE})
@Test
public void testIsUidNetworkingBlocked_withSystemUid() throws Exception {
// Refer to NetworkPolicyManagerService#isUidNetworkingBlockedInternal(), this test is to
@@ -103,6 +106,7 @@
}
}
+ @RequiredProperties({DATA_SAVER_MODE})
@Test
public void testIsUidNetworkingBlocked_withDataSaverMode() throws Exception {
// Refer to NetworkPolicyManagerService#isUidNetworkingBlockedInternal(), this test is to
@@ -182,6 +186,7 @@
}
}
+ @RequiredProperties({BATTERY_SAVER_MODE})
@Test
public void testIsUidNetworkingBlocked_withPowerSaverMode() throws Exception {
// Refer to NetworkPolicyManagerService#isUidNetworkingBlockedInternal(), this test is to
@@ -209,6 +214,7 @@
}
}
+ @RequiredProperties({DATA_SAVER_MODE})
@Test
public void testIsUidRestrictedOnMeteredNetworks() throws Exception {
try {
diff --git a/tests/cts/net/src/android/net/cts/BatteryStatsManagerTest.java b/tests/cts/net/src/android/net/cts/BatteryStatsManagerTest.java
index a54fd64..86642ea 100644
--- a/tests/cts/net/src/android/net/cts/BatteryStatsManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/BatteryStatsManagerTest.java
@@ -35,6 +35,7 @@
import android.os.Build;
import android.os.connectivity.CellularBatteryStats;
import android.os.connectivity.WifiBatteryStats;
+import android.platform.test.annotations.AppModeFull;
import android.util.Log;
import androidx.test.runner.AndroidJUnit4;
@@ -80,6 +81,7 @@
}
@Test
+ @AppModeFull(reason = "Cannot get CHANGE_NETWORK_STATE to request wifi/cell in instant mode")
@SkipPresubmit(reason = "Virtual hardware does not support wifi battery stats")
public void testReportNetworkInterfaceForTransports() throws Exception {
try {
@@ -132,6 +134,7 @@
}
@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
+ @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
@Test
public void testReportNetworkInterfaceForTransports_throwsSecurityException()
throws Exception {
diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
index a19c7a6..cd5281f 100644
--- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -72,6 +72,7 @@
import static com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity;
import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
+import static com.android.modules.utils.build.SdkLevel.isAtLeastS;
import static com.android.networkstack.apishim.ConstantsShim.BLOCKED_REASON_LOCKDOWN_VPN;
import static com.android.networkstack.apishim.ConstantsShim.BLOCKED_REASON_NONE;
import static com.android.testutils.MiscAsserts.assertThrows;
@@ -499,6 +500,7 @@
@Test
public void testGetAllNetworkStateSnapshots()
throws InterruptedException {
+ assumeTrue(mPackageManager.hasSystemFeature(FEATURE_TELEPHONY));
// Make sure cell is active to retrieve IMSI for verification in later step.
final Network cellNetwork = mCtsNetUtils.connectToCell();
final String subscriberId = getSubscriberIdForCellNetwork(cellNetwork);
@@ -936,8 +938,8 @@
// noticeably flaky.
Thread.sleep(NO_CALLBACK_TIMEOUT_MS);
- // TODO: BUG (b/189868426): this should also apply to listens
- if (!useListen) {
+ // For R- frameworks, listens will receive duplicated callbacks. See b/189868426.
+ if (isAtLeastS() || !useListen) {
assertEquals("PendingIntent should only be received once", 1, receivedCount.get());
}
} finally {
@@ -952,8 +954,8 @@
boolean useListen) {
assertArrayEquals(filed.networkCapabilities.getCapabilities(),
broadcasted.networkCapabilities.getCapabilities());
- // TODO: BUG (b/189868426): this should also apply to listens
- if (useListen) return;
+ // For R- frameworks, listens will receive duplicated callbacks. See b/189868426.
+ if (!isAtLeastS() && useListen) return;
assertArrayEquals(filed.networkCapabilities.getTransportTypes(),
broadcasted.networkCapabilities.getTransportTypes());
}
@@ -1077,7 +1079,7 @@
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");
+ fail("Unexpected format from cmd netpolicy, policyString = " + policyString);
}
return m.group(1);
}
diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt
index ccc9416..7c380e3 100644
--- a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt
+++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt
@@ -101,6 +101,7 @@
import com.android.testutils.TestableNetworkCallback
import org.junit.After
import org.junit.Assert.assertArrayEquals
+import org.junit.Assume.assumeFalse
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -1034,6 +1035,9 @@
@Test
fun testQosCallbackRegisterWithUnregister() {
+ // Instant apps can't bind sockets to localhost
+ // TODO: use @AppModeFull when supported by DevSdkIgnoreRunner
+ assumeFalse(realContext.packageManager.isInstantApp())
val (agent, socket) = setupForQosCallbackTesting()
val qosCallback = TestableQosCallback()
@@ -1060,6 +1064,9 @@
@Test
fun testQosCallbackOnQosSession() {
+ // Instant apps can't bind sockets to localhost
+ // TODO: use @AppModeFull when supported by DevSdkIgnoreRunner
+ assumeFalse(realContext.packageManager.isInstantApp())
val (agent, socket) = setupForQosCallbackTesting()
val qosCallback = TestableQosCallback()
Executors.newSingleThreadExecutor().let { executor ->
@@ -1104,6 +1111,9 @@
@Test
fun testQosCallbackOnError() {
+ // Instant apps can't bind sockets to localhost
+ // TODO: use @AppModeFull when supported by DevSdkIgnoreRunner
+ assumeFalse(realContext.packageManager.isInstantApp())
val (agent, socket) = setupForQosCallbackTesting()
val qosCallback = TestableQosCallback()
Executors.newSingleThreadExecutor().let { executor ->
@@ -1142,6 +1152,9 @@
@Test
fun testQosCallbackIdsAreMappedCorrectly() {
+ // Instant apps can't bind sockets to localhost
+ // TODO: use @AppModeFull when supported by DevSdkIgnoreRunner
+ assumeFalse(realContext.packageManager.isInstantApp())
val (agent, socket) = setupForQosCallbackTesting()
val qosCallback1 = TestableQosCallback()
val qosCallback2 = TestableQosCallback()
@@ -1182,6 +1195,9 @@
@Test
fun testQosCallbackWhenNetworkReleased() {
+ // Instant apps can't bind sockets to localhost
+ // TODO: use @AppModeFull when supported by DevSdkIgnoreRunner
+ assumeFalse(realContext.packageManager.isInstantApp())
val (agent, socket) = setupForQosCallbackTesting()
Executors.newSingleThreadExecutor().let { executor ->
try {
diff --git a/tests/cts/net/src/android/net/cts/PacProxyManagerTest.java b/tests/cts/net/src/android/net/cts/PacProxyManagerTest.java
index 7d5e9ff..a20f1cc 100644
--- a/tests/cts/net/src/android/net/cts/PacProxyManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/PacProxyManagerTest.java
@@ -35,6 +35,7 @@
import android.net.ProxyInfo;
import android.net.Uri;
import android.os.Build;
+import android.platform.test.annotations.AppModeFull;
import android.util.Log;
import android.util.Range;
@@ -145,6 +146,7 @@
}
}
+ @AppModeFull(reason = "Instant apps can't bind sockets to localhost for a test proxy server")
@Test
public void testSetCurrentProxyScriptUrl() throws Exception {
// Register a PacProxyInstalledListener
diff --git a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java
index 0a5e506..bd1b74a 100644
--- a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java
+++ b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java
@@ -361,6 +361,7 @@
@Test
public void testRequestLatestEntitlementResult() throws Exception {
assumeTrue(mTM.isTetheringSupported());
+ assumeTrue(mPm.hasSystemFeature(FEATURE_TELEPHONY));
// Verify that requestLatestTetheringEntitlementResult() can get entitlement
// result(TETHER_ERROR_ENTITLEMENT_UNKNOWN due to invalid downstream type) via listener.
assertEntitlementResult(listener -> mTM.requestLatestTetheringEntitlementResult(
diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
index 78fbc4a..6d7d3d2 100644
--- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -5450,6 +5450,8 @@
// the follow-up network disconnection will be processed first.
mWiFiNetworkAgent.setKeepaliveResponseDelay(3 * TIMEOUT_MS);
ka.stop();
+ // Call stop() twice shouldn't result in crash, b/182586681.
+ ka.stop();
// Make sure the stop has been processed. Wait for executor idle is needed to prevent
// flaky since the actual stop call to the service is delegated to executor thread.
@@ -5747,37 +5749,59 @@
@Test
public void testNetworkCallbackMaximum() throws Exception {
final int MAX_REQUESTS = 100;
- final int CALLBACKS = 89;
- final int INTENTS = 11;
+ final int CALLBACKS = 87;
+ final int DIFF_INTENTS = 10;
+ final int SAME_INTENTS = 10;
final int SYSTEM_ONLY_MAX_REQUESTS = 250;
- assertEquals(MAX_REQUESTS, CALLBACKS + INTENTS);
+ // Assert 1 (Default request filed before testing) + CALLBACKS + DIFF_INTENTS +
+ // 1 (same intent) = MAX_REQUESTS - 1, since the capacity is MAX_REQUEST - 1.
+ assertEquals(MAX_REQUESTS - 1, 1 + CALLBACKS + DIFF_INTENTS + 1);
NetworkRequest networkRequest = new NetworkRequest.Builder().build();
ArrayList<Object> registered = new ArrayList<>();
- int j = 0;
- while (j++ < CALLBACKS / 2) {
- NetworkCallback cb = new NetworkCallback();
- mCm.requestNetwork(networkRequest, cb);
+ for (int j = 0; j < CALLBACKS; j++) {
+ final NetworkCallback cb = new NetworkCallback();
+ if (j < CALLBACKS / 2) {
+ mCm.requestNetwork(networkRequest, cb);
+ } else {
+ mCm.registerNetworkCallback(networkRequest, cb);
+ }
registered.add(cb);
}
- while (j++ < CALLBACKS) {
- NetworkCallback cb = new NetworkCallback();
- mCm.registerNetworkCallback(networkRequest, cb);
- registered.add(cb);
+
+ // Since ConnectivityService will de-duplicate the request with the same intent,
+ // register multiple times does not really increase multiple requests.
+ final PendingIntent same_pi = PendingIntent.getBroadcast(mContext, 0 /* requestCode */,
+ new Intent("same"), FLAG_IMMUTABLE);
+ for (int j = 0; j < SAME_INTENTS; j++) {
+ mCm.registerNetworkCallback(networkRequest, same_pi);
+ // Wait for the requests with the same intent to be de-duplicated. Because
+ // ConnectivityService side incrementCountOrThrow in binder, decrementCount in handler
+ // thread, waitForIdle is needed to ensure decrementCount being invoked for same intent
+ // requests before doing further tests.
+ waitForIdle();
}
- j = 0;
- while (j++ < INTENTS / 2) {
- final PendingIntent pi = PendingIntent.getBroadcast(mContext, 0 /* requestCode */,
- new Intent("a" + j), FLAG_IMMUTABLE);
- mCm.requestNetwork(networkRequest, pi);
- registered.add(pi);
+ for (int j = 0; j < SAME_INTENTS; j++) {
+ mCm.requestNetwork(networkRequest, same_pi);
+ // Wait for the requests with the same intent to be de-duplicated.
+ // Refer to the reason above.
+ waitForIdle();
}
- while (j++ < INTENTS) {
- final PendingIntent pi = PendingIntent.getBroadcast(mContext, 0 /* requestCode */,
- new Intent("b" + j), FLAG_IMMUTABLE);
- mCm.registerNetworkCallback(networkRequest, pi);
- registered.add(pi);
+ registered.add(same_pi);
+
+ for (int j = 0; j < DIFF_INTENTS; j++) {
+ if (j < DIFF_INTENTS / 2) {
+ final PendingIntent pi = PendingIntent.getBroadcast(mContext, 0 /* requestCode */,
+ new Intent("a" + j), FLAG_IMMUTABLE);
+ mCm.requestNetwork(networkRequest, pi);
+ registered.add(pi);
+ } else {
+ final PendingIntent pi = PendingIntent.getBroadcast(mContext, 0 /* requestCode */,
+ new Intent("b" + j), FLAG_IMMUTABLE);
+ mCm.registerNetworkCallback(networkRequest, pi);
+ registered.add(pi);
+ }
}
// Test that the limit is enforced when MAX_REQUESTS simultaneous requests are added.
@@ -5827,10 +5851,10 @@
for (Object o : registered) {
if (o instanceof NetworkCallback) {
- mCm.unregisterNetworkCallback((NetworkCallback)o);
+ mCm.unregisterNetworkCallback((NetworkCallback) o);
}
if (o instanceof PendingIntent) {
- mCm.unregisterNetworkCallback((PendingIntent)o);
+ mCm.unregisterNetworkCallback((PendingIntent) o);
}
}
waitForIdle();
@@ -13414,43 +13438,43 @@
}
@Test
- public void testSetMobileDataPreferredUids_noIssueToFactory() throws Exception {
- // First set mobile data preferred uid to create a multi-layer requests: 1. listen for
+ public void testMultilayerRequestsOfSetMobileDataPreferredUids() throws Exception {
+ // First set mobile data preferred uid to create a multi-layer requests: 1. request for
// cellular, 2. track the default network for fallback.
setAndUpdateMobileDataPreferredUids(
Set.of(PRIMARY_USER_HANDLE.getUid(TEST_PACKAGE_UID)));
final HandlerThread handlerThread = new HandlerThread("MockFactory");
handlerThread.start();
- NetworkCapabilities internetFilter = new NetworkCapabilities()
+ final NetworkCapabilities cellFilter = new NetworkCapabilities()
+ .addTransportType(TRANSPORT_CELLULAR)
.addCapability(NET_CAPABILITY_INTERNET)
.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
- final MockNetworkFactory internetFactory = new MockNetworkFactory(handlerThread.getLooper(),
- mServiceContext, "internetFactory", internetFilter, mCsHandlerThread);
- internetFactory.setScoreFilter(40);
+ final MockNetworkFactory cellFactory = new MockNetworkFactory(handlerThread.getLooper(),
+ mServiceContext, "cellFactory", cellFilter, mCsHandlerThread);
+ cellFactory.setScoreFilter(40);
try {
- internetFactory.register();
- // Default internet request only. The first request is listen for cellular network,
- // which is never sent to factories (it's a LISTEN, not requestable). The second
- // fallback request is TRACK_DEFAULT which is also not sent to factories.
- internetFactory.expectRequestAdds(1);
- internetFactory.assertRequestCountEquals(1);
+ cellFactory.register();
+ // Default internet request and the mobile data preferred request.
+ cellFactory.expectRequestAdds(2);
+ cellFactory.assertRequestCountEquals(2);
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.connect(true);
- // The internet factory however is outscored, and should lose its requests.
- internetFactory.expectRequestRemove();
- internetFactory.assertRequestCountEquals(0);
+ // The cellFactory however is outscored, and should lose default internet request.
+ // But it should still see mobile data preferred request.
+ cellFactory.expectRequestRemove();
+ cellFactory.assertRequestCountEquals(1);
- mCellNetworkAgent.disconnect();
+ mWiFiNetworkAgent.disconnect();
// The network satisfying the default internet request has disconnected, so the
- // internetFactory sees the default request again.
- internetFactory.expectRequestAdds(1);
- internetFactory.assertRequestCountEquals(1);
+ // cellFactory sees the default internet requests again.
+ cellFactory.expectRequestAdd();
+ cellFactory.assertRequestCountEquals(2);
} finally {
- internetFactory.terminate();
+ cellFactory.terminate();
handlerThread.quitSafely();
}
}
diff --git a/tests/unit/java/com/android/server/connectivity/NetworkNotificationManagerTest.java b/tests/unit/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
index c924535..07deeef 100644
--- a/tests/unit/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
+++ b/tests/unit/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
@@ -16,6 +16,7 @@
package com.android.server.connectivity;
+import static android.app.Notification.FLAG_AUTO_CANCEL;
import static android.app.Notification.FLAG_ONGOING_EVENT;
import static com.android.server.connectivity.NetworkNotificationManager.NotificationType.LOST_INTERNET;
@@ -80,6 +81,8 @@
private static final String TEST_SSID = "Test SSID";
private static final String TEST_EXTRA_INFO = "extra";
+ private static final int TEST_NOTIF_ID = 101;
+ private static final String TEST_NOTIF_TAG = NetworkNotificationManager.tagFor(TEST_NOTIF_ID);
static final NetworkCapabilities CELL_CAPABILITIES = new NetworkCapabilities();
static final NetworkCapabilities WIFI_CAPABILITIES = new NetworkCapabilities();
static final NetworkCapabilities VPN_CAPABILITIES = new NetworkCapabilities();
@@ -141,6 +144,7 @@
}
when(mResources.getStringArray(R.array.network_switch_type_name))
.thenReturn(transportNames);
+ when(mResources.getBoolean(R.bool.config_autoCancelNetworkNotifications)).thenReturn(true);
mManager = new NetworkNotificationManager(mCtx, mTelephonyManager);
}
@@ -237,57 +241,65 @@
verify(mNotificationManager, never()).notify(any(), anyInt(), any());
}
- private void assertNotification(NotificationType type, boolean ongoing) {
- final int id = 101;
- final String tag = NetworkNotificationManager.tagFor(id);
+ private void assertNotification(NotificationType type, boolean ongoing, boolean autoCancel) {
final ArgumentCaptor<Notification> noteCaptor = ArgumentCaptor.forClass(Notification.class);
- mManager.showNotification(id, type, mWifiNai, mCellNai, null, false);
- verify(mNotificationManager, times(1)).notify(eq(tag), eq(type.eventId),
+ mManager.showNotification(TEST_NOTIF_ID, type, mWifiNai, mCellNai, null, false);
+ verify(mNotificationManager, times(1)).notify(eq(TEST_NOTIF_TAG), eq(type.eventId),
noteCaptor.capture());
assertEquals("Notification ongoing flag should be " + (ongoing ? "set" : "unset"),
ongoing, (noteCaptor.getValue().flags & FLAG_ONGOING_EVENT) != 0);
+ assertEquals("Notification autocancel flag should be " + (autoCancel ? "set" : "unset"),
+ autoCancel, (noteCaptor.getValue().flags & FLAG_AUTO_CANCEL) != 0);
}
@Test
public void testDuplicatedNotificationsNoInternetThenSignIn() {
- final int id = 101;
- final String tag = NetworkNotificationManager.tagFor(id);
-
// Show first NO_INTERNET
- assertNotification(NO_INTERNET, false /* ongoing */);
+ assertNotification(NO_INTERNET, false /* ongoing */, true /* autoCancel */);
// Captive portal detection triggers SIGN_IN a bit later, clearing the previous NO_INTERNET
- assertNotification(SIGN_IN, false /* ongoing */);
- verify(mNotificationManager, times(1)).cancel(eq(tag), eq(NO_INTERNET.eventId));
+ assertNotification(SIGN_IN, false /* ongoing */, true /* autoCancel */);
+ verify(mNotificationManager, times(1)).cancel(eq(TEST_NOTIF_TAG), eq(NO_INTERNET.eventId));
// Network disconnects
- mManager.clearNotification(id);
- verify(mNotificationManager, times(1)).cancel(eq(tag), eq(SIGN_IN.eventId));
+ mManager.clearNotification(TEST_NOTIF_ID);
+ verify(mNotificationManager, times(1)).cancel(eq(TEST_NOTIF_TAG), eq(SIGN_IN.eventId));
}
@Test
public void testOngoingSignInNotification() {
doReturn(true).when(mResources).getBoolean(R.bool.config_ongoingSignInNotification);
- final int id = 101;
- final String tag = NetworkNotificationManager.tagFor(id);
// Show first NO_INTERNET
- assertNotification(NO_INTERNET, false /* ongoing */);
+ assertNotification(NO_INTERNET, false /* ongoing */, true /* autoCancel */);
// Captive portal detection triggers SIGN_IN a bit later, clearing the previous NO_INTERNET
- assertNotification(SIGN_IN, true /* ongoing */);
- verify(mNotificationManager, times(1)).cancel(eq(tag), eq(NO_INTERNET.eventId));
+ assertNotification(SIGN_IN, true /* ongoing */, true /* autoCancel */);
+ verify(mNotificationManager, times(1)).cancel(eq(TEST_NOTIF_TAG), eq(NO_INTERNET.eventId));
// Network disconnects
- mManager.clearNotification(id);
- verify(mNotificationManager, times(1)).cancel(eq(tag), eq(SIGN_IN.eventId));
+ mManager.clearNotification(TEST_NOTIF_ID);
+ verify(mNotificationManager, times(1)).cancel(eq(TEST_NOTIF_TAG), eq(SIGN_IN.eventId));
+ }
+
+ @Test
+ public void testNoAutoCancelNotification() {
+ doReturn(false).when(mResources).getBoolean(R.bool.config_autoCancelNetworkNotifications);
+
+ // Show NO_INTERNET, then SIGN_IN
+ assertNotification(NO_INTERNET, false /* ongoing */, false /* autoCancel */);
+ assertNotification(SIGN_IN, false /* ongoing */, false /* autoCancel */);
+ verify(mNotificationManager, times(1)).cancel(eq(TEST_NOTIF_TAG), eq(NO_INTERNET.eventId));
+
+ mManager.clearNotification(TEST_NOTIF_ID);
+ verify(mNotificationManager, times(1)).cancel(eq(TEST_NOTIF_TAG), eq(SIGN_IN.eventId));
}
@Test
public void testDuplicatedNotificationsSignInThenNoInternet() {
- final int id = 101;
- final String tag = NetworkNotificationManager.tagFor(id);
+ final int id = TEST_NOTIF_ID;
+ final String tag = TEST_NOTIF_TAG;
// Show first SIGN_IN
mManager.showNotification(id, SIGN_IN, mWifiNai, mCellNai, null, false);
@@ -306,8 +318,8 @@
@Test
public void testClearNotificationByType() {
- final int id = 101;
- final String tag = NetworkNotificationManager.tagFor(id);
+ final int id = TEST_NOTIF_ID;
+ final String tag = TEST_NOTIF_TAG;
// clearNotification(int id, NotificationType notifyType) will check if given type is equal
// to previous type or not. If they are equal then clear the notification; if they are not