diff --git a/tests/cts/multidevices/snippet/Android.bp b/tests/cts/multidevices/snippet/Android.bp index c94087e2e6..9e1878331e 100644 --- a/tests/cts/multidevices/snippet/Android.bp +++ b/tests/cts/multidevices/snippet/Android.bp @@ -16,6 +16,20 @@ package { default_applicable_licenses: ["Android-Apache-2.0"], } +java_library { + name: "ConnectivityWifiP2pMultiDevicesSnippetLib", + srcs: [ + "Wifip2pMultiDevicesSnippet.kt", + ], + static_libs: [ + "mobly-snippet-lib", + "cts-net-utils", + ], + visibility: [ + "//packages/modules/Connectivity/tests/cts/tethering", + ], +} + android_test_helper_app { name: "connectivity_multi_devices_snippet", defaults: [ diff --git a/tests/cts/tethering/Android.bp b/tests/cts/tethering/Android.bp index a1e0797490..38042851a3 100644 --- a/tests/cts/tethering/Android.bp +++ b/tests/cts/tethering/Android.bp @@ -30,9 +30,11 @@ java_defaults { srcs: [ "src/**/*.java", + "src/**/*.kt", ], static_libs: [ + "ConnectivityWifiP2pMultiDevicesSnippetLib", "TetheringCommonTests", "com.android.net.flags-aconfig-java", "compatibility-device-util-axt", diff --git a/tests/cts/tethering/AndroidManifest.xml b/tests/cts/tethering/AndroidManifest.xml index bad722bb0f..aede2d724e 100644 --- a/tests/cts/tethering/AndroidManifest.xml +++ b/tests/cts/tethering/AndroidManifest.xml @@ -20,6 +20,9 @@ + + diff --git a/tests/cts/tethering/src/android/tethering/cts/TetheringWifiP2pTest.kt b/tests/cts/tethering/src/android/tethering/cts/TetheringWifiP2pTest.kt new file mode 100644 index 0000000000..e7e9fdd9f2 --- /dev/null +++ b/tests/cts/tethering/src/android/tethering/cts/TetheringWifiP2pTest.kt @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2025 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.tethering.cts + +import android.Manifest.permission.LOG_COMPAT_CHANGE +import android.Manifest.permission.READ_COMPAT_CHANGE_CONFIG +import android.app.compat.CompatChanges +import android.content.pm.PackageManager +import android.net.NetworkCapabilities.NET_CAPABILITY_LOCAL_NETWORK +import android.net.NetworkCapabilities.TRANSPORT_WIFI +import android.net.NetworkRequest +import android.net.connectivity.ConnectivityCompatChanges +import android.os.Build +import android.provider.DeviceConfig +import android.text.TextUtils +import androidx.test.platform.app.InstrumentationRegistry +import com.android.testutils.AutoReleaseNetworkCallbackRule +import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo +import com.android.testutils.DevSdkIgnoreRunner +import com.android.testutils.DeviceConfigRule +import com.android.testutils.RecorderCallback.CallbackEntry.Available +import com.android.testutils.RecorderCallback.CallbackEntry.CapabilitiesChanged +import com.android.testutils.RecorderCallback.CallbackEntry.LinkPropertiesChanged +import com.android.testutils.TestableNetworkCallback +import com.android.testutils.runAsShell +import com.google.snippet.connectivity.Wifip2pMultiDevicesSnippet +import java.util.Random +import org.junit.Assert.assertEquals +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue +import org.junit.Assume.assumeTrue +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +@IgnoreUpTo(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) +@RunWith(DevSdkIgnoreRunner::class) +class TetheringWifiP2pTest { + // For manipulating feature flag before and after testing. + @get:Rule + val deviceConfigRule = DeviceConfigRule() + + @get:Rule + val networkCallbackRule = AutoReleaseNetworkCallbackRule() + + companion object { + // Shamelessly copied from TetheringConfiguration. + private const val TETHERING_LOCAL_NETWORK_AGENT = "tethering_local_network_agent" + private const val WIFIP2PGO_LOCAL_NETWORK_AGENT = "wifip2pgo_local_network_agent" + } + + private val context = InstrumentationRegistry.getInstrumentation().getTargetContext() + private val pm = context.packageManager!! + + private fun assumeMatchNonThreadLocalNetworksEnabled() { + assumeTrue(runAsShell(READ_COMPAT_CHANGE_CONFIG, LOG_COMPAT_CHANGE) { + CompatChanges.isChangeEnabled( + ConnectivityCompatChanges.ENABLE_MATCH_NON_THREAD_LOCAL_NETWORKS + ) + }) + } + + private fun getRandomString(): String { + return "%09d".format(Random().nextInt(1_000_000_000)) + } + + @Test + fun testWifiP2pGoNetworkAgent_networkCallbacks() { + // Check preconditions. + assumeMatchNonThreadLocalNetworksEnabled() + assumeTrue(pm.hasSystemFeature(PackageManager.FEATURE_WIFI)) + assumeTrue(pm.hasSystemFeature(PackageManager.FEATURE_WIFI_DIRECT)) + deviceConfigRule.setConfig( + DeviceConfig.NAMESPACE_TETHERING, + TETHERING_LOCAL_NETWORK_AGENT, + "1" + ) + deviceConfigRule.setConfig( + DeviceConfig.NAMESPACE_TETHERING, + WIFIP2PGO_LOCAL_NETWORK_AGENT, + "1" + ) + + val cb = TestableNetworkCallback() + val request = NetworkRequest.Builder().addCapability(NET_CAPABILITY_LOCAL_NETWORK) + .addTransportType(TRANSPORT_WIFI).build() + networkCallbackRule.registerNetworkCallback(request, cb) + + val wifiP2pSnippet = Wifip2pMultiDevicesSnippet() + try { + wifiP2pSnippet.startWifiP2p() + wifiP2pSnippet.createGroup("DIRECT-" + getRandomString(), getRandomString()) + + val availableEvent = cb.expect() + // Verify Capabilities. + val capEvent = cb.eventuallyExpect() + assertEquals(availableEvent.network, capEvent.network) + assertTrue(capEvent.caps.hasCapability(NET_CAPABILITY_LOCAL_NETWORK)) + assertTrue(capEvent.caps.hasTransport(TRANSPORT_WIFI)) + + // Verify LinkProperties. + val lpEvent = cb.eventuallyExpect() + assertEquals(capEvent.network, lpEvent.network) + assertFalse(TextUtils.isEmpty(lpEvent.lp.interfaceName)) + // At least 1 Ipv4 address and route. + assertTrue(lpEvent.lp.hasIPv4Address()) + assertTrue(lpEvent.lp.routes.size >= 1) + } finally { + wifiP2pSnippet.stopWifiP2p() + } + } +}