summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--flags/Android.bp1
-rw-r--r--framework/java/android/net/wifi/SoftApConfiguration.java44
-rw-r--r--framework/java/android/net/wifi/rtt/ResponderConfig.java2
-rw-r--r--framework/tests/src/android/net/wifi/SoftApConfigurationTest.java17
-rw-r--r--service/java/com/android/server/wifi/HalDeviceManager.java2
-rw-r--r--service/java/com/android/server/wifi/WifiApConfigStore.java2
-rw-r--r--service/java/com/android/server/wifi/WifiInjector.java2
-rw-r--r--service/java/com/android/server/wifi/WifiShellCommand.java45
-rw-r--r--service/java/com/android/server/wifi/mainline_supplicant/MainlineSupplicant.java41
-rw-r--r--service/java/com/android/server/wifi/mainline_supplicant/MainlineSupplicantStaIfaceCallback.java9
-rw-r--r--service/tests/wifitests/src/com/android/server/wifi/WifiApConfigStoreTest.java4
-rw-r--r--service/tests/wifitests/src/com/android/server/wifi/mainline_supplicant/MainlineSupplicantTest.java6
-rw-r--r--tests/hostsidetests/multidevices/com.google.snippet.wifi/direct/WifiP2pManagerSnippet.java46
-rw-r--r--tests/hostsidetests/multidevices/test/Android.bp7
-rw-r--r--tests/hostsidetests/multidevices/test/aware/AndroidTestNew.xml6
-rw-r--r--tests/hostsidetests/multidevices/test/aware/wifi_aware_discovery_ranging_test.py27
-rw-r--r--tests/hostsidetests/multidevices/test/aware/wifi_aware_network_test.py29
-rw-r--r--tests/hostsidetests/multidevices/test/direct/AndroidTest.xml10
-rw-r--r--tests/hostsidetests/multidevices/test/direct/integration/Android.bp27
-rw-r--r--tests/hostsidetests/multidevices/test/direct/integration/wifi_p2p_lib.py564
-rw-r--r--tests/hostsidetests/multidevices/test/direct/integration/wifi_p2p_manager_test.py256
-rw-r--r--tests/hostsidetests/multidevices/test/direct/p2p_utils.py66
-rw-r--r--tests/hostsidetests/multidevices/test/direct/wifi_direct_test_suite.py (renamed from tests/hostsidetests/multidevices/test/direct/cts_wifi_direct_test_suite.py)6
-rw-r--r--tests/hostsidetests/multidevices/test/softap/AndroidTest.xml6
24 files changed, 1136 insertions, 89 deletions
diff --git a/flags/Android.bp b/flags/Android.bp
index 99ba39a590..3052a39aef 100644
--- a/flags/Android.bp
+++ b/flags/Android.bp
@@ -37,6 +37,7 @@ java_aconfig_library {
"//frameworks/opt/net/wifi/libs/WifiTrackerLib:__subpackages__",
"//packages/modules/Wifi:__subpackages__",
"//cts/tests/tests/wifi:__subpackages__",
+ "//cts/tests/tests/security",
],
}
diff --git a/framework/java/android/net/wifi/SoftApConfiguration.java b/framework/java/android/net/wifi/SoftApConfiguration.java
index 92efcf72cb..086c816b71 100644
--- a/framework/java/android/net/wifi/SoftApConfiguration.java
+++ b/framework/java/android/net/wifi/SoftApConfiguration.java
@@ -1426,6 +1426,45 @@ public final class SoftApConfiguration implements Parcelable {
mIsClientIsolationEnabled = other.mIsClientIsolationEnabled;
}
+ /**
+ * Builds the {@link SoftApConfiguration} without any check.
+ *
+ * @return A new {@link SoftApConfiguration}, as configured by previous method calls.
+ *
+ * @hide
+ */
+ @VisibleForTesting
+ @NonNull
+ public SoftApConfiguration buildWithoutCheck() {
+ return new SoftApConfiguration(
+ mWifiSsid,
+ mBssid,
+ mPassphrase,
+ mHiddenSsid,
+ mChannels,
+ mSecurityType,
+ mMaxNumberOfClients,
+ mAutoShutdownEnabled,
+ mShutdownTimeoutMillis,
+ mClientControlByUser,
+ mBlockedClientList,
+ mAllowedClientList,
+ mMacRandomizationSetting,
+ mBridgedModeOpportunisticShutdownEnabled,
+ mIeee80211axEnabled,
+ mIeee80211beEnabled,
+ mIsUserConfiguration,
+ mBridgedModeOpportunisticShutdownTimeoutMillis,
+ mVendorElements,
+ mPersistentRandomizedMacAddress,
+ mAllowedAcsChannels2g,
+ mAllowedAcsChannels5g,
+ mAllowedAcsChannels6g,
+ mMaxChannelBandwidth,
+ mVendorData,
+ mIsClientIsolationEnabled);
+ }
+
/**
* Builds the {@link SoftApConfiguration}.
*
@@ -1451,6 +1490,11 @@ public final class SoftApConfiguration implements Parcelable {
REMOVE_ZERO_FOR_TIMEOUT_SETTING) && mShutdownTimeoutMillis == DEFAULT_TIMEOUT) {
mShutdownTimeoutMillis = 0; // Use 0 for legacy app.
}
+
+ if (SdkLevel.isAtLeastB() && !mIeee80211axEnabled) {
+ // Force 11BE to false since 11ax has dependency with 11AX.
+ mIeee80211beEnabled = false;
+ }
return new SoftApConfiguration(
mWifiSsid,
mBssid,
diff --git a/framework/java/android/net/wifi/rtt/ResponderConfig.java b/framework/java/android/net/wifi/rtt/ResponderConfig.java
index ffa98499ed..7d950eeabd 100644
--- a/framework/java/android/net/wifi/rtt/ResponderConfig.java
+++ b/framework/java/android/net/wifi/rtt/ResponderConfig.java
@@ -1074,7 +1074,7 @@ public final class ResponderConfig implements Parcelable {
if (secureRangingConfig != null) {
builder.setSecureRangingConfig(secureRangingConfig);
}
- return builder.build();
+ return new ResponderConfig(builder);
}
};
diff --git a/framework/tests/src/android/net/wifi/SoftApConfigurationTest.java b/framework/tests/src/android/net/wifi/SoftApConfigurationTest.java
index 7e4f5ea310..9938a6a990 100644
--- a/framework/tests/src/android/net/wifi/SoftApConfigurationTest.java
+++ b/framework/tests/src/android/net/wifi/SoftApConfigurationTest.java
@@ -962,4 +962,21 @@ public class SoftApConfigurationTest {
OuiKeyedData unparceledOuiKeyedData = unparceled.getVendorData().get(0);
assertEquals(bundle.getInt(fieldKey), unparceledOuiKeyedData.getData().getInt(fieldKey));
}
+
+ @Test
+ public void testForce11BeToFalseWhen11AxIsFalse() {
+ assumeTrue(SdkLevel.isAtLeastB());
+ // Only 11be is false, it should be ok.
+ SoftApConfiguration config = new SoftApConfiguration.Builder()
+ .setIeee80211axEnabled(true)
+ .setIeee80211beEnabled(false).build();
+ assertTrue(config.isIeee80211axEnabled());
+ assertFalse(config.isIeee80211beEnabled());
+ // Only 11ax is false, 11be should force to false too.
+ config = new SoftApConfiguration.Builder()
+ .setIeee80211axEnabled(false)
+ .setIeee80211beEnabled(true).build();
+ assertFalse(config.isIeee80211axEnabled());
+ assertFalse(config.isIeee80211beEnabled());
+ }
}
diff --git a/service/java/com/android/server/wifi/HalDeviceManager.java b/service/java/com/android/server/wifi/HalDeviceManager.java
index 227ca28f13..9a0bf0ae64 100644
--- a/service/java/com/android/server/wifi/HalDeviceManager.java
+++ b/service/java/com/android/server/wifi/HalDeviceManager.java
@@ -1584,7 +1584,7 @@ public class HalDeviceManager {
@Override
public void onSubsystemRestart(int status) {
Log.i(TAG, "onSubsystemRestart");
- mEventHandler.post(() -> {
+ mEventHandler.postAtFrontOfQueue(() -> {
Log.i(TAG, "IWifiEventCallback.onSubsystemRestart. Status: " + status);
synchronized (mLock) {
Log.i(TAG, "Attempting to invoke mSubsystemRestartListener");
diff --git a/service/java/com/android/server/wifi/WifiApConfigStore.java b/service/java/com/android/server/wifi/WifiApConfigStore.java
index c4a22f52ad..efe527a016 100644
--- a/service/java/com/android/server/wifi/WifiApConfigStore.java
+++ b/service/java/com/android/server/wifi/WifiApConfigStore.java
@@ -733,7 +733,7 @@ public class WifiApConfigStore {
}
// Hostapd requires 11AX to configure 11BE
- if (SdkLevel.isAtLeastT() && apConfig.isIeee80211beEnabled()
+ if (SdkLevel.isAtLeastB() && apConfig.isIeee80211beEnabled()
&& !apConfig.isIeee80211axEnabledInternal()) {
Log.d(TAG, "11AX is required when configuring 11BE");
return false;
diff --git a/service/java/com/android/server/wifi/WifiInjector.java b/service/java/com/android/server/wifi/WifiInjector.java
index 15b7c508d3..300f850d51 100644
--- a/service/java/com/android/server/wifi/WifiInjector.java
+++ b/service/java/com/android/server/wifi/WifiInjector.java
@@ -356,7 +356,7 @@ public class WifiInjector {
mSupplicantStaIfaceHal = new SupplicantStaIfaceHal(
mContext, mWifiMonitor, mFrameworkFacade, mWifiHandler, mClock, mWifiMetrics,
mWifiGlobals, mSsidTranslator, this);
- mMainlineSupplicant = new MainlineSupplicant();
+ mMainlineSupplicant = new MainlineSupplicant(mWifiThreadRunner);
mHostapdHal = new HostapdHal(mContext, mWifiHandler);
mWifiCondManager = (WifiNl80211Manager) mContext.getSystemService(
Context.WIFI_NL80211_SERVICE);
diff --git a/service/java/com/android/server/wifi/WifiShellCommand.java b/service/java/com/android/server/wifi/WifiShellCommand.java
index aad4de03ca..bd49b590ab 100644
--- a/service/java/com/android/server/wifi/WifiShellCommand.java
+++ b/service/java/com/android/server/wifi/WifiShellCommand.java
@@ -1256,6 +1256,10 @@ public class WifiShellCommand extends BasicShellCommandHandler {
new ParceledListSlice<>(Collections.emptyList()), SHELL_PACKAGE_NAME,
WifiManager.ACTION_REMOVE_SUGGESTION_DISCONNECT);
return 0;
+ case "clear-all-suggestions":
+ mWifiThreadRunner.post(() -> mWifiNetworkSuggestionsManager.clear(),
+ "shell#clear-all-suggestions");
+ return 0;
case "list-suggestions": {
List<WifiNetworkSuggestion> suggestions =
mWifiService.getNetworkSuggestions(SHELL_PACKAGE_NAME).getList();
@@ -3268,6 +3272,8 @@ public class WifiShellCommand extends BasicShellCommandHandler {
pw.println(" Lists all suggested networks on this device");
pw.println(" list-suggestions-from-app <package name>");
pw.println(" Lists the suggested networks from the app");
+ pw.println(" clear-all-suggestions");
+ pw.println(" Clear all suggestions added into this device");
pw.println(" set-emergency-callback-mode enabled|disabled");
pw.println(" Sets whether Emergency Callback Mode (ECBM) is enabled.");
pw.println(" Equivalent to receiving the "
@@ -3442,15 +3448,36 @@ public class WifiShellCommand extends BasicShellCommandHandler {
if (suggestions == null || suggestions.isEmpty()) {
pw.println("No suggestions on this device");
} else {
- pw.println("SSID Security type(s)");
- for (WifiNetworkSuggestion suggestion : suggestions) {
- pw.println(String.format("%-32s %-4s",
- WifiInfo.sanitizeSsid(suggestion.getWifiConfiguration().SSID),
- suggestion.getWifiConfiguration().getSecurityParamsList().stream()
- .map(p -> WifiConfiguration.getSecurityTypeName(
- p.getSecurityType())
- + (p.isAddedByAutoUpgrade() ? "^" : ""))
- .collect(Collectors.joining("/"))));
+ if (SdkLevel.isAtLeastS()) {
+ /*
+ * Print out SubId on S and above because WifiNetworkSuggestion.getSubscriptionId()
+ * is supported from Android S and above.
+ */
+ String format = "%-24s %-24s %-12s %-12s";
+ pw.println(String.format(format, "SSID", "Security type(s)", "CarrierId", "SubId"));
+ for (WifiNetworkSuggestion suggestion : suggestions) {
+ pw.println(String.format(format,
+ WifiInfo.sanitizeSsid(suggestion.getWifiConfiguration().SSID),
+ suggestion.getWifiConfiguration().getSecurityParamsList().stream()
+ .map(p -> WifiConfiguration.getSecurityTypeName(
+ p.getSecurityType())
+ + (p.isAddedByAutoUpgrade() ? "^" : ""))
+ .collect(Collectors.joining("/")),
+ suggestion.getCarrierId(), suggestion.getSubscriptionId()));
+ }
+ } else {
+ String format = "%-24s %-24s %-12s";
+ pw.println(String.format(format, "SSID", "Security type(s)", "CarrierId"));
+ for (WifiNetworkSuggestion suggestion : suggestions) {
+ pw.println(String.format(format,
+ WifiInfo.sanitizeSsid(suggestion.getWifiConfiguration().SSID),
+ suggestion.getWifiConfiguration().getSecurityParamsList().stream()
+ .map(p -> WifiConfiguration.getSecurityTypeName(
+ p.getSecurityType())
+ + (p.isAddedByAutoUpgrade() ? "^" : ""))
+ .collect(Collectors.joining("/")),
+ suggestion.getCarrierId()));
+ }
}
}
}
diff --git a/service/java/com/android/server/wifi/mainline_supplicant/MainlineSupplicant.java b/service/java/com/android/server/wifi/mainline_supplicant/MainlineSupplicant.java
index bc87d018b8..6310577077 100644
--- a/service/java/com/android/server/wifi/mainline_supplicant/MainlineSupplicant.java
+++ b/service/java/com/android/server/wifi/mainline_supplicant/MainlineSupplicant.java
@@ -24,10 +24,12 @@ import android.os.RemoteException;
import android.os.ServiceSpecificException;
import android.system.wifi.mainline_supplicant.IMainlineSupplicant;
import android.system.wifi.mainline_supplicant.IStaInterface;
+import android.system.wifi.mainline_supplicant.IStaInterfaceCallback;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.wifi.WifiNative;
+import com.android.server.wifi.WifiThreadRunner;
import com.android.wifi.flags.Flags;
import java.util.HashMap;
@@ -48,13 +50,16 @@ public class MainlineSupplicant {
private IMainlineSupplicant mIMainlineSupplicant;
private final Object mLock = new Object();
+ private final WifiThreadRunner mWifiThreadRunner;
private SupplicantDeathRecipient mServiceDeathRecipient;
private WifiNative.SupplicantDeathEventHandler mFrameworkDeathHandler;
private CountDownLatch mWaitForDeathLatch;
private final boolean mIsServiceAvailable;
private Map<String, IStaInterface> mActiveStaIfaces = new HashMap<>();
+ private Map<String, IStaInterfaceCallback> mStaIfaceCallbacks = new HashMap<>();
- public MainlineSupplicant() {
+ public MainlineSupplicant(@NonNull WifiThreadRunner wifiThreadRunner) {
+ mWifiThreadRunner = wifiThreadRunner;
mServiceDeathRecipient = new SupplicantDeathRecipient();
mIsServiceAvailable = canServiceBeAccessed();
}
@@ -125,6 +130,7 @@ public class MainlineSupplicant {
synchronized (mLock) {
mIMainlineSupplicant = null;
mActiveStaIfaces.clear();
+ mStaIfaceCallbacks.clear();
}
}
@@ -195,7 +201,15 @@ public class MainlineSupplicant {
try {
IStaInterface staIface = mIMainlineSupplicant.addStaInterface(ifaceName);
+ IStaInterfaceCallback callback = new MainlineSupplicantStaIfaceCallback(
+ this, ifaceName, mWifiThreadRunner);
+ if (!registerStaIfaceCallback(staIface, callback)) {
+ Log.i(TAG, "Unable to register callback with interface " + ifaceName);
+ return false;
+ }
mActiveStaIfaces.put(ifaceName, staIface);
+ // Keep callback in a store to avoid recycling by the garbage collector
+ mStaIfaceCallbacks.put(ifaceName, callback);
Log.i(TAG, "Added STA interface " + ifaceName);
return true;
} catch (ServiceSpecificException e) {
@@ -230,6 +244,7 @@ public class MainlineSupplicant {
try {
mIMainlineSupplicant.removeStaInterface(ifaceName);
mActiveStaIfaces.remove(ifaceName);
+ mStaIfaceCallbacks.remove(ifaceName);
Log.i(TAG, "Removed STA interface " + ifaceName);
return true;
} catch (ServiceSpecificException e) {
@@ -242,6 +257,30 @@ public class MainlineSupplicant {
}
/**
+ * Register a callback with the provided STA interface.
+ *
+ * @return true if the registration was successful, false otherwise.
+ */
+ private boolean registerStaIfaceCallback(@NonNull IStaInterface iface,
+ @NonNull IStaInterfaceCallback callback) {
+ synchronized (mLock) {
+ final String methodName = "registerStaIfaceCallback";
+ if (iface == null || callback == null) {
+ return false;
+ }
+ try {
+ iface.registerCallback(callback);
+ return true;
+ } catch (ServiceSpecificException e) {
+ handleServiceSpecificException(e, methodName);
+ } catch (RemoteException e) {
+ handleRemoteException(e, methodName);
+ }
+ return false;
+ }
+ }
+
+ /**
* Stop the mainline supplicant process.
*/
public void stopService() {
diff --git a/service/java/com/android/server/wifi/mainline_supplicant/MainlineSupplicantStaIfaceCallback.java b/service/java/com/android/server/wifi/mainline_supplicant/MainlineSupplicantStaIfaceCallback.java
index 0f7510194a..20cda62861 100644
--- a/service/java/com/android/server/wifi/mainline_supplicant/MainlineSupplicantStaIfaceCallback.java
+++ b/service/java/com/android/server/wifi/mainline_supplicant/MainlineSupplicantStaIfaceCallback.java
@@ -17,23 +17,24 @@
package com.android.server.wifi.mainline_supplicant;
import android.annotation.NonNull;
-import android.os.Handler;
import android.system.wifi.mainline_supplicant.IStaInterfaceCallback;
import android.system.wifi.mainline_supplicant.UsdMessageInfo;
+import com.android.server.wifi.WifiThreadRunner;
+
/**
* Implementation of the mainline supplicant {@link IStaInterfaceCallback}.
*/
public class MainlineSupplicantStaIfaceCallback extends IStaInterfaceCallback.Stub {
private final MainlineSupplicant mMainlineSupplicant;
private final String mIfaceName;
- private final Handler mHandler;
+ private final WifiThreadRunner mWifiThreadRunner;
MainlineSupplicantStaIfaceCallback(@NonNull MainlineSupplicant mainlineSupplicant,
- @NonNull String ifaceName, @NonNull Handler handler) {
+ @NonNull String ifaceName, @NonNull WifiThreadRunner wifiThreadRunner) {
mMainlineSupplicant = mainlineSupplicant;
mIfaceName = ifaceName;
- mHandler = handler;
+ mWifiThreadRunner = wifiThreadRunner;
}
/**
diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiApConfigStoreTest.java b/service/tests/wifitests/src/com/android/server/wifi/WifiApConfigStoreTest.java
index c939a44181..b7b86871d0 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/WifiApConfigStoreTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/WifiApConfigStoreTest.java
@@ -948,13 +948,13 @@ public class WifiApConfigStoreTest extends WifiBaseTest {
@Test
public void test11BERequires11AXConfigInValidateApWifiConfigurationCheck() {
- assumeTrue(SdkLevel.isAtLeastT());
+ assumeTrue(SdkLevel.isAtLeastB());
assertFalse(WifiApConfigStore.validateApWifiConfiguration(
new SoftApConfiguration.Builder()
.setSsid(TEST_DEFAULT_HOTSPOT_SSID)
.setIeee80211axEnabled(false)
.setIeee80211beEnabled(true)
- .build(), true, mContext, mWifiNative));
+ .buildWithoutCheck(), true, mContext, mWifiNative));
}
/**
diff --git a/service/tests/wifitests/src/com/android/server/wifi/mainline_supplicant/MainlineSupplicantTest.java b/service/tests/wifitests/src/com/android/server/wifi/mainline_supplicant/MainlineSupplicantTest.java
index 7094446810..d1c25a5078 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/mainline_supplicant/MainlineSupplicantTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/mainline_supplicant/MainlineSupplicantTest.java
@@ -28,11 +28,14 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.net.wifi.util.Environment;
+import android.os.Handler;
import android.os.IBinder;
+import android.os.test.TestLooper;
import android.system.wifi.mainline_supplicant.IMainlineSupplicant;
import android.system.wifi.mainline_supplicant.IStaInterface;
import com.android.server.wifi.WifiNative;
+import com.android.server.wifi.WifiThreadRunner;
import org.junit.Before;
import org.junit.Test;
@@ -51,6 +54,7 @@ public class MainlineSupplicantTest {
private @Mock WifiNative.SupplicantDeathEventHandler mFrameworkDeathHandler;
private @Mock IStaInterface mIStaInterface;
private MainlineSupplicantSpy mDut;
+ private TestLooper mLooper = new TestLooper();
private ArgumentCaptor<IBinder.DeathRecipient> mDeathRecipientCaptor =
ArgumentCaptor.forClass(IBinder.DeathRecipient.class);
@@ -58,7 +62,7 @@ public class MainlineSupplicantTest {
// Spy version of this class allows us to override methods for testing.
private class MainlineSupplicantSpy extends MainlineSupplicant {
MainlineSupplicantSpy() {
- super();
+ super(new WifiThreadRunner(new Handler(mLooper.getLooper())));
}
@Override
diff --git a/tests/hostsidetests/multidevices/com.google.snippet.wifi/direct/WifiP2pManagerSnippet.java b/tests/hostsidetests/multidevices/com.google.snippet.wifi/direct/WifiP2pManagerSnippet.java
index 0a82ca4bac..3bf57c246a 100644
--- a/tests/hostsidetests/multidevices/com.google.snippet.wifi/direct/WifiP2pManagerSnippet.java
+++ b/tests/hostsidetests/multidevices/com.google.snippet.wifi/direct/WifiP2pManagerSnippet.java
@@ -400,6 +400,52 @@ public class WifiP2pManagerSnippet implements Snippet {
}
/**
+ * Get p2p connect PIN code after calling {@link #wifiP2pConnect(JSONObject,Integer)} with
+ * WPS PIN.
+ *
+ * @param deviceName The name of the device to connect.
+ * @return The generated PIN as a String.
+ * @throws Throwable If failed to get PIN code.
+ */
+ @Rpc(description = "Get p2p connect PIN code after calling wifiP2pConnect with WPS PIN.")
+ public String wifiP2pGetKeypadPinCode(String deviceName) throws Throwable {
+ // Wait for the 'Invitation sent' dialog to appear
+ if (!mUiDevice.wait(Until.hasObject(By.text("Invitation to connect")),
+ UI_ACTION_LONG_TIMEOUT_MS)) {
+ throw new WifiP2pManagerException(
+ "Invitation sent dialog did not appear within timeout.");
+ }
+ if (!mUiDevice.wait(Until.hasObject(By.text(deviceName)), UI_ACTION_SHORT_TIMEOUT_MS)) {
+ throw new WifiP2pManagerException(
+ "The connect invitation is not triggered by expected peer device.");
+ }
+ // Find the UI lement with text='PIN:'
+ UiObject2 pinLabel = mUiDevice.findObject(By.text("PIN:"));
+ if (pinLabel == null) {
+ throw new WifiP2pManagerException("PIN label not found.");
+ }
+ Log.d("pinLabel = " + pinLabel);
+ // Get the sibling UI element that contains the PIN code. Use regex pattern "\d+" as PIN
+ // code must be composed entirely of numbers.
+ Pattern pattern = Pattern.compile("\\d+");
+ UiObject2 pinValue = pinLabel.getParent().findObject(By.text(pattern));
+ if (pinValue == null) {
+ throw new WifiP2pManagerException("Failed to find Pin code UI element.");
+ }
+ String pinCode = pinValue.getText();
+ Log.d("Retrieved PIN code: " + pinCode);
+ // Click 'OK' to close the PIN code alert
+ UiObject2 okButton = mUiDevice.findObject(By.text("Accept").clazz(Button.class));
+ if (okButton == null) {
+ throw new WifiP2pManagerException(
+ "OK button not found in the p2p connection invitation pop-up window.");
+ }
+ okButton.click();
+ Log.d("Closed the p2p connect invitation pop-up window.");
+ return pinCode;
+ }
+
+ /**
* Enters the given PIN code to accept a P2P connection invitation.
*
* @param pinCode The PIN to enter.
diff --git a/tests/hostsidetests/multidevices/test/Android.bp b/tests/hostsidetests/multidevices/test/Android.bp
index 2adbfb5739..3d3ef73ee5 100644
--- a/tests/hostsidetests/multidevices/test/Android.bp
+++ b/tests/hostsidetests/multidevices/test/Android.bp
@@ -118,14 +118,14 @@ python_test_host {
}
python_test_host {
- name: "CtsWifiDirectTests",
- main: "direct/cts_wifi_direct_test_suite.py",
+ name: "WifiDirectTests",
+ main: "direct/wifi_direct_test_suite.py",
srcs: [
"direct/group_owner_negotiation_test.py",
"direct/group_owner_test.py",
"direct/group_owner_with_config_test.py",
"direct/service_discovery_test.py",
- "direct/cts_wifi_direct_test_suite.py",
+ "direct/wifi_direct_test_suite.py",
],
test_config: "direct/AndroidTest.xml",
libs: [
@@ -142,7 +142,6 @@ python_test_host {
},
test_suites: [
"general-tests",
- "cts-v-host",
],
}
diff --git a/tests/hostsidetests/multidevices/test/aware/AndroidTestNew.xml b/tests/hostsidetests/multidevices/test/aware/AndroidTestNew.xml
index 244257efec..69de107885 100644
--- a/tests/hostsidetests/multidevices/test/aware/AndroidTestNew.xml
+++ b/tests/hostsidetests/multidevices/test/aware/AndroidTestNew.xml
@@ -21,18 +21,12 @@
<target_preparer class="AndroidDeviceFeaturesCheckDecorator">
<option name="required_feature" value="android.hardware.wifi.aware" />
</target_preparer>
- <target_preparer class="AndroidMainlineModulesCheckDecorator">
- <option name="mainline_module_package_name" value="com.google.android.wifi" />
- </target_preparer>
<target_preparer class="AndroidInstallAppsDecorator" />
</device>
<device name="AndroidDevice">
<target_preparer class="AndroidDeviceFeaturesCheckDecorator">
<option name="required_feature" value="android.hardware.wifi.aware" />
</target_preparer>
- <target_preparer class="AndroidMainlineModulesCheckDecorator">
- <option name="mainline_module_package_name" value="com.google.android.wifi" />
- </target_preparer>
<target_preparer class="AndroidInstallAppsDecorator" />
</device>
diff --git a/tests/hostsidetests/multidevices/test/aware/wifi_aware_discovery_ranging_test.py b/tests/hostsidetests/multidevices/test/aware/wifi_aware_discovery_ranging_test.py
index 6e9a7b77d5..6951f36e5b 100644
--- a/tests/hostsidetests/multidevices/test/aware/wifi_aware_discovery_ranging_test.py
+++ b/tests/hostsidetests/multidevices/test/aware/wifi_aware_discovery_ranging_test.py
@@ -92,12 +92,16 @@ class WifiAwareDiscoveryRangingTest(base_test.BaseTestClass):
self.publisher = self.ads[0]
self.subscriber = self.ads[1]
- def setup_device(device: android_device.AndroidDevice):
- device.load_snippet('wifi', _SNIPPET_PACKAGE_NAME)
- device.wifi.wifiEnable()
- wifi_test_utils.set_screen_on_and_unlock(device)
- wifi_test_utils.enable_wifi_verbose_logging(device)
- # Device capability check
+ # Device setup
+ utils.concurrent_exec(
+ self._setup_device,
+ ((self.publisher,), (self.subscriber,)),
+ max_workers=2,
+ raise_on_exception=True,
+ )
+
+ # Device capability check
+ for device in [self.publisher, self.subscriber]:
asserts.abort_class_if(
not device.wifi.wifiAwareIsSupported(),
f'{device} does not support Wi-Fi Aware.',
@@ -111,12 +115,11 @@ class WifiAwareDiscoveryRangingTest(base_test.BaseTestClass):
f'{device} does not support Wi-Fi RTT.',
)
- utils.concurrent_exec(
- setup_device,
- ((self.publisher,), (self.subscriber,)),
- max_workers=2,
- raise_on_exception=True,
- )
+ def _setup_device(self, device: android_device.AndroidDevice):
+ device.load_snippet('wifi', _SNIPPET_PACKAGE_NAME)
+ device.wifi.wifiEnable()
+ wifi_test_utils.set_screen_on_and_unlock(device)
+ wifi_test_utils.enable_wifi_verbose_logging(device)
def test_discovery_ranging_to_peer_handle(self) -> None:
"""Test ranging to a Wi-Fi Aware peer handle.
diff --git a/tests/hostsidetests/multidevices/test/aware/wifi_aware_network_test.py b/tests/hostsidetests/multidevices/test/aware/wifi_aware_network_test.py
index f711b6dccc..c0d406603e 100644
--- a/tests/hostsidetests/multidevices/test/aware/wifi_aware_network_test.py
+++ b/tests/hostsidetests/multidevices/test/aware/wifi_aware_network_test.py
@@ -81,27 +81,30 @@ class WifiAwareNetworkTest(base_test.BaseTestClass):
self.publisher = self.ads[0]
self.subscriber = self.ads[1]
- def setup_device(device: android_device.AndroidDevice):
- device.load_snippet('wifi', _SNIPPET_PACKAGE_NAME)
- device.wifi.wifiEnable()
- wifi_test_utils.set_screen_on_and_unlock(device)
- wifi_test_utils.enable_wifi_verbose_logging(device)
- # Device capability check
+ # Device setup
+ utils.concurrent_exec(
+ self._setup_device,
+ ((self.publisher,), (self.subscriber,)),
+ max_workers=2,
+ raise_on_exception=True,
+ )
+
+ # Device capability check
+ for device in [self.publisher, self.subscriber]:
asserts.abort_class_if(
not device.wifi.wifiAwareIsSupported(),
f'{device} does not support Wi-Fi Aware.',
)
asserts.abort_class_if(
not device.wifi.wifiAwareIsAvailable(),
- f'{device} Wi-Fi Aware is not available.',
+ f'Wi-Fi Aware is not available on {device}.',
)
- utils.concurrent_exec(
- setup_device,
- ((self.publisher,), (self.subscriber,)),
- max_workers=2,
- raise_on_exception=True,
- )
+ def _setup_device(self, device: android_device.AndroidDevice):
+ device.load_snippet('wifi', _SNIPPET_PACKAGE_NAME)
+ device.wifi.wifiEnable()
+ wifi_test_utils.set_screen_on_and_unlock(device)
+ wifi_test_utils.enable_wifi_verbose_logging(device)
@ApiTest(
apis=[
diff --git a/tests/hostsidetests/multidevices/test/direct/AndroidTest.xml b/tests/hostsidetests/multidevices/test/direct/AndroidTest.xml
index 63f3af4ada..6da3197442 100644
--- a/tests/hostsidetests/multidevices/test/direct/AndroidTest.xml
+++ b/tests/hostsidetests/multidevices/test/direct/AndroidTest.xml
@@ -10,7 +10,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<configuration description="Test config for Wi-Fi Direct multi-device CTS tests">
+<configuration description="Test config for Wi-Fi Direct multi-device tests">
<option name="test-suite-tag" value="cts-v-host" />
<option name="config-descriptor:metadata" key="component" value="wifi" />
<option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
@@ -21,23 +21,17 @@
<target_preparer class="AndroidDeviceFeaturesCheckDecorator">
<option name="required_feature" value="android.hardware.wifi.direct" />
</target_preparer>
- <target_preparer class="AndroidMainlineModulesCheckDecorator">
- <option name="mainline_module_package_name" value="com.google.android.wifi" />
- </target_preparer>
<target_preparer class="AndroidInstallAppsDecorator" />
</device>
<device name="AndroidDevice">
<target_preparer class="AndroidDeviceFeaturesCheckDecorator">
<option name="required_feature" value="android.hardware.wifi.direct" />
</target_preparer>
- <target_preparer class="AndroidMainlineModulesCheckDecorator">
- <option name="mainline_module_package_name" value="com.google.android.wifi" />
- </target_preparer>
<target_preparer class="AndroidInstallAppsDecorator" />
</device>
<test class="MoblyAospPackageTest" />
- <option name="mobly_pkg" key="file" value="CtsWifiDirectTests" />
+ <option name="mobly_pkg" key="file" value="WifiDirectTests" />
<option name="build_apk" key="file" value="wifi_mobly_snippet.apk" />
</configuration> \ No newline at end of file
diff --git a/tests/hostsidetests/multidevices/test/direct/integration/Android.bp b/tests/hostsidetests/multidevices/test/direct/integration/Android.bp
index 95d120633a..6ee454d34a 100644
--- a/tests/hostsidetests/multidevices/test/direct/integration/Android.bp
+++ b/tests/hostsidetests/multidevices/test/direct/integration/Android.bp
@@ -43,3 +43,30 @@ python_test_host {
},
test_suites: ["general-tests"],
}
+
+python_test_host {
+ name: "WifiP2pManagerTestCases",
+ main: "wifi_p2p_manager_test.py",
+ srcs: [
+ "wifi_p2p_manager_test.py",
+ ],
+ libs: [
+ "mobly",
+ "wifi_direct_constants",
+ "wifi_direct_test_utils",
+ "wifi_p2p_lib",
+ "wifi_test_utils",
+ "platform-test-py-annotations",
+ ],
+ device_common_data: [":wifi_mobly_snippet"],
+ test_options: {
+ unit_test: false,
+ tags: ["mobly"],
+ },
+ test_suites: ["general-tests"],
+ version: {
+ py3: {
+ embedded_launcher: true,
+ },
+ },
+}
diff --git a/tests/hostsidetests/multidevices/test/direct/integration/wifi_p2p_lib.py b/tests/hostsidetests/multidevices/test/direct/integration/wifi_p2p_lib.py
index 566145c651..c6a50e6719 100644
--- a/tests/hostsidetests/multidevices/test/direct/integration/wifi_p2p_lib.py
+++ b/tests/hostsidetests/multidevices/test/direct/integration/wifi_p2p_lib.py
@@ -27,6 +27,7 @@
# Lint as: python3
+from collections.abc import Sequence
import datetime
import time
@@ -35,19 +36,74 @@ from direct import p2p_utils
from mobly import asserts
from mobly.controllers import android_device
from mobly.controllers.android_device_lib import adb
+from mobly.controllers.android_device_lib import callback_handler_v2
+from mobly.snippet import errors
_DEFAULT_TIMEOUT = datetime.timedelta(seconds=30)
_DEFAULT_SLEEPTIME = 5
+_DEFAULT_FUNCTION_SWITCH_TIME = 10
+_DEFAULT_SERVICE_WAITING_TIME = 20
+_NORMAL_TIMEOUT = datetime.timedelta(seconds=20)
P2P_CONNECT_NEGOTIATION = 0
P2P_CONNECT_JOIN = 1
P2P_CONNECT_INVITATION = 2
+######################################################
+# Wifi P2p local service type
+####################################################
+P2P_LOCAL_SERVICE_UPNP = 0
+P2P_LOCAL_SERVICE_IPP = 1
+P2P_LOCAL_SERVICE_AFP = 2
+
+######################################################
+# Wifi P2p local service event
+####################################################
+
+DNSSD_EVENT = 'WifiP2pOnDnsSdServiceAvailable'
+DNSSD_TXRECORD_EVENT = 'WifiP2pOnDnsSdTxtRecordAvailable'
+UPNP_EVENT = 'WifiP2pOnUpnpServiceAvailable'
+
+DNSSD_EVENT_INSTANCENAME_KEY = 'InstanceName'
+DNSSD_EVENT_REGISTRATIONTYPE_KEY = 'RegistrationType'
+DNSSD_TXRECORD_EVENT_FULLDOMAINNAME_KEY = 'FullDomainName'
+DNSSD_TXRECORD_EVENT_TXRECORDMAP_KEY = 'TxtRecordMap'
+UPNP_EVENT_SERVICELIST_KEY = 'ServiceList'
+
+
+######################################################
+# Wifi P2p UPnP MediaRenderer local service
+######################################################
+class UpnpTestData():
+ av_transport = 'urn:schemas-upnp-org:service:AVTransport:1'
+ connection_manager = 'urn:schemas-upnp-org:service:ConnectionManager:1'
+ service_type = 'urn:schemas-upnp-org:device:MediaRenderer:1'
+ uuid = '6859dede-8574-59ab-9332-123456789011'
+ rootdevice = 'upnp:rootdevice'
+
+
+######################################################
+# Wifi P2p Bonjour IPP & AFP local service
+######################################################
+class IppTestData():
+ ipp_instance_name = 'MyPrinter'
+ ipp_registration_type = '_ipp._tcp'
+ ipp_domain_name = 'myprinter._ipp._tcp.local.'
+ ipp_txt_record = {'txtvers': '1', 'pdl': 'application/postscript'}
+
+
+class AfpTestData():
+ afp_instance_name = 'Example'
+ afp_registration_type = '_afpovertcp._tcp'
+ afp_domain_name = 'example._afpovertcp._tcp.local.'
+ afp_txt_record = {}
+
# Trigger p2p connect to device_go from device_gc.
def p2p_connect(
device_gc: p2p_utils.DeviceState,
device_go: p2p_utils.DeviceState,
+ is_reconnect,
wps_setup,
p2p_connect_type=P2P_CONNECT_NEGOTIATION,
go_ad=None,
@@ -57,15 +113,21 @@ def p2p_connect(
Args:
device_gc: The android device (Client)
device_go: The android device (GO)
+ is_reconnect: boolean, if persist group is exist, is_reconnect is true,
+ otherswise is false.
wps_setup: which wps connection would like to use
p2p_connect_type: enumeration, which type this p2p connection is
go_ad: The group owner android device which is used for the invitation
connection
"""
device_gc.ad.log.info(
- 'Create p2p connection from %s to %s via wps: %s type %d'
- % (device_gc.ad.serial, device_go.ad.serial, wps_setup, p2p_connect_type)
+ 'Create p2p connection from %s to %s via wps: %s type %d',
+ device_gc.ad.serial,
+ device_go.ad.serial,
+ wps_setup,
+ p2p_connect_type,
)
+
if p2p_connect_type == P2P_CONNECT_INVITATION:
if go_ad is None:
go_ad = device_gc
@@ -77,11 +139,11 @@ def p2p_connect(
elif p2p_connect_type == P2P_CONNECT_JOIN:
peer_p2p_device = p2p_utils.discover_group_owner(
client=device_gc,
- group_owner_address=device_go.p2p_device.device_address
+ group_owner_address=device_go.p2p_device.device_address,
)
asserts.assert_true(
peer_p2p_device.is_group_owner,
- f"P2p device {peer_p2p_device} should be group owner.",
+ f'P2p device {peer_p2p_device} should be group owner.',
)
else:
p2p_utils.discover_p2p_peer(device_gc, device_go)
@@ -95,7 +157,10 @@ def p2p_connect(
device_address=device_go.p2p_device.device_address,
wps_setup=wps_setup,
)
- p2p_utils.p2p_connect(device_gc, device_go, p2p_config)
+ if not is_reconnect:
+ p2p_utils.p2p_connect(device_gc, device_go, p2p_config)
+ else:
+ p2p_utils.p2p_reconnect(device_gc, device_go, p2p_config)
def is_go(ad):
@@ -127,15 +192,14 @@ def p2p_go_ip(ad):
Returns:
GO IP address
"""
- ad.log.info('p2p go ip')
event_handler = ad.wifi.wifiP2pRequestConnectionInfo()
- ad.log.info(type(event_handler))
result = event_handler.waitAndGet(
event_name=constants.ON_CONNECTION_INFO_AVAILABLE,
timeout=_DEFAULT_TIMEOUT.total_seconds(),
)
+ go_flag = result.data['isGroupOwner']
ip = result.data['groupOwnerHostAddress'].replace('/', '')
- ad.log.info('p2p go ip: %s' % ip)
+ ad.log.info('is_go:%s, p2p ip: %s', go_flag, ip)
return ip
@@ -175,6 +239,474 @@ def p2p_connection_ping_test(dut: android_device.AndroidDevice, peer_ip: str):
dut.log.info(results)
+def gen_test_data(service_category):
+ """Based on service category to generator Test Data.
+
+ Args:
+ service_category: P2p local service type, Upnp or Bonjour
+
+ Returns:
+ TestData
+ """
+ test_data = []
+ if service_category == P2P_LOCAL_SERVICE_UPNP:
+ test_data.append(UpnpTestData.uuid)
+ test_data.append(UpnpTestData.service_type)
+ test_data.append(
+ [UpnpTestData.av_transport, UpnpTestData.connection_manager]
+ )
+ elif service_category == P2P_LOCAL_SERVICE_IPP:
+ test_data.append(IppTestData.ipp_instance_name)
+ test_data.append(IppTestData.ipp_registration_type)
+ test_data.append(IppTestData.ipp_txt_record)
+ elif service_category == P2P_LOCAL_SERVICE_AFP:
+ test_data.append(AfpTestData.afp_instance_name)
+ test_data.append(AfpTestData.afp_registration_type)
+ test_data.append(AfpTestData.afp_txt_record)
+
+ return test_data
+
+
+def create_p2p_local_service(ad, service_category):
+ """Based on service_category to create p2p local service on an Android device ad.
+
+ Args:
+ ad: The android device
+ service_category: p2p local service type, UPNP / IPP / AFP,
+ """
+ test_data = gen_test_data(service_category)
+ ad.log.info(
+ 'LocalService = %s, %s, %s', test_data[0], test_data[1], test_data[2]
+ )
+ if service_category == P2P_LOCAL_SERVICE_UPNP:
+ ad.wifi.wifiP2pAddUpnpLocalService(test_data[0], test_data[1], test_data[2])
+ elif (
+ service_category == P2P_LOCAL_SERVICE_IPP
+ or service_category == P2P_LOCAL_SERVICE_AFP
+ ):
+ ad.wifi.wifiP2pAddBonjourLocalService(
+ test_data[0], test_data[1], test_data[2]
+ )
+
+
+def gen_expect_test_data(service_type, query_string1, query_string2):
+ """Based on serviceCategory to generator expect serviceList.
+
+ Args:
+ service_type: P2p local service type, Upnp or Bonjour
+ query_string1: Query String, NonNull
+ query_string2: Query String, used for Bonjour, Nullable
+
+ Returns:
+ expect_service_list: expect data generated.
+ """
+ expect_service_list = {}
+ if (
+ service_type
+ == WifiP2PEnums.WifiP2pServiceInfo.WIFI_P2P_SERVICE_TYPE_BONJOUR
+ ):
+ ipp_service = WifiP2PEnums.WifiP2pDnsSdServiceResponse()
+ afp_service = WifiP2PEnums.WifiP2pDnsSdServiceResponse()
+ if query_string1 == IppTestData.ipp_registration_type:
+ if query_string2 == IppTestData.ipp_instance_name:
+ ipp_service.instance_name = ''
+ ipp_service.registration_type = ''
+ ipp_service.full_domain_name = IppTestData.ipp_domain_name
+ ipp_service.txt_record_map = IppTestData.ipp_txt_record
+ expect_service_list[ipp_service.to_string()] = 1
+ return expect_service_list
+ ipp_service.instance_name = IppTestData.ipp_instance_name
+ ipp_service.registration_type = (
+ IppTestData.ipp_registration_type + '.local.'
+ )
+ ipp_service.full_domain_name = ''
+ ipp_service.txt_record_map = ''
+ expect_service_list[ipp_service.to_string()] = 1
+ return expect_service_list
+ elif query_string1 == AfpTestData.afp_registration_type:
+ if query_string2 == AfpTestData.afp_instance_name:
+ afp_service.instance_name = ''
+ afp_service.registration_type = ''
+ afp_service.full_domain_name = AfpTestData.afp_domain_name
+ afp_service.txt_record_map = AfpTestData.afp_txt_record
+ expect_service_list[afp_service.to_string()] = 1
+ return expect_service_list
+ ipp_service.instance_name = IppTestData.ipp_instance_name
+ ipp_service.registration_type = (
+ IppTestData.ipp_registration_type + '.local.'
+ )
+ ipp_service.full_domain_name = ''
+ ipp_service.txt_record_map = ''
+ expect_service_list[ipp_service.to_string()] = 1
+
+ ipp_service.instance_name = ''
+ ipp_service.registration_type = ''
+ ipp_service.full_domain_name = IppTestData.ipp_domain_name
+ ipp_service.txt_record_map = IppTestData.ipp_txt_record
+ expect_service_list[ipp_service.to_string()] = 1
+
+ afp_service.instance_name = AfpTestData.afp_instance_name
+ afp_service.registration_type = (
+ AfpTestData.afp_registration_type + '.local.'
+ )
+ afp_service.full_domain_name = ''
+ afp_service.txt_record_map = ''
+ expect_service_list[afp_service.to_string()] = 1
+
+ afp_service.instance_name = ''
+ afp_service.registration_type = ''
+ afp_service.full_domain_name = AfpTestData.afp_domain_name
+ afp_service.txt_record_map = AfpTestData.afp_txt_record
+ expect_service_list[afp_service.to_string()] = 1
+
+ return expect_service_list
+ elif (
+ service_type == WifiP2PEnums.WifiP2pServiceInfo.WIFI_P2P_SERVICE_TYPE_UPNP
+ ):
+ upnp_service = (
+ 'uuid:' + UpnpTestData.uuid + '::' + (UpnpTestData.rootdevice)
+ )
+ expect_service_list[upnp_service] = 1
+ if query_string1 != 'upnp:rootdevice':
+ upnp_service = (
+ 'uuid:' + UpnpTestData.uuid + ('::' + UpnpTestData.av_transport)
+ )
+ expect_service_list[upnp_service] = 1
+ upnp_service = (
+ 'uuid:' + UpnpTestData.uuid + ('::' + UpnpTestData.connection_manager)
+ )
+ expect_service_list[upnp_service] = 1
+ upnp_service = (
+ 'uuid:' + UpnpTestData.uuid + ('::' + UpnpTestData.service_type)
+ )
+ expect_service_list[upnp_service] = 1
+ upnp_service = 'uuid:' + UpnpTestData.uuid
+ expect_service_list[upnp_service] = 1
+
+ return expect_service_list
+
+
+def check_service_query_result(service_list, expect_service_list):
+ """Check serviceList same as expectServiceList or not.
+
+ Args:
+ service_list: ServiceList which get from query result
+ expect_service_list: ServiceList which hardcode in genExpectTestData
+
+ Returns:
+ True: serviceList same as expectServiceList
+ False:Exist discrepancy between serviceList and expectServiceList
+ """
+ temp_service_list = service_list.copy()
+ temp_expect_service_list = expect_service_list.copy()
+ for service in service_list.keys():
+ if service in expect_service_list:
+ del temp_service_list[service]
+ del temp_expect_service_list[service]
+ return not temp_expect_service_list and not temp_service_list
+
+
+def _check_all_expect_data(expect_data: dict[str, int]) -> bool:
+ for _, v in expect_data.items():
+ if v == 1:
+ return False
+ return True
+
+
+def request_service_and_check_result(
+ ad_service_provider: p2p_utils.DeviceState,
+ ad_service_receiver: p2p_utils.DeviceState,
+ service_type: int,
+ query_string1,
+ query_string2,
+):
+ """Based on service type and query info, check service request result.
+
+ Check same as expect or not on an Android device ad_service_receiver.
+ And remove p2p service request after result check.
+
+ Args:
+ ad_service_provider: The android device which provide p2p local service
+ ad_service_receiver: The android device which query p2p local service
+ service_type: P2p local service type, Upnp or Bonjour
+ query_string1: Query String, NonNull
+ query_string2: Query String, used for Bonjour, Nullable
+
+ Returns:
+ 0: if service request result is as expected.
+ """
+ expect_data = gen_expect_test_data(service_type, query_string1, query_string2)
+ p2p_utils.discover_p2p_peer(ad_service_receiver, ad_service_provider)
+ ad_service_receiver.ad.wifi.wifiP2pStopPeerDiscovery()
+ ad_service_receiver.ad.wifi.wifiP2pClearServiceRequests()
+ time.sleep(_DEFAULT_FUNCTION_SWITCH_TIME)
+
+ service_id = 0
+ if (
+ service_type
+ == WifiP2PEnums.WifiP2pServiceInfo.WIFI_P2P_SERVICE_TYPE_BONJOUR
+ ):
+ ad_service_receiver.ad.log.info(
+ 'Request bonjour service in %s with Query String %s and %s '
+ % (ad_service_receiver.ad.serial, query_string1, query_string2)
+ )
+ ad_service_receiver.ad.log.info('expectData 1st %s' % expect_data)
+ if query_string1:
+ service_id = ad_service_receiver.ad.wifi.wifiP2pAddBonjourServiceRequest(
+ query_string2, # instanceName
+ query_string1, # serviceType
+ )
+ else:
+ service_id = ad_service_receiver.ad.wifi.wifiP2pAddServiceRequest(
+ service_type
+ )
+ time.sleep(_DEFAULT_FUNCTION_SWITCH_TIME)
+ ad_service_receiver.ad.log.info('service request id %s' % service_id)
+ p2p_utils.set_dns_sd_response_listeners(ad_service_receiver)
+ ad_service_receiver.ad.wifi.wifiP2pDiscoverServices()
+ ad_service_receiver.ad.log.info('Check Service Listener')
+ time.sleep(_DEFAULT_SERVICE_WAITING_TIME)
+ check_discovered_dns_sd_response(
+ ad_service_receiver,
+ expected_responses=expect_data,
+ expected_src_device_address=(
+ ad_service_provider.p2p_device.device_address
+ ),
+ channel_id=ad_service_receiver.channel_ids[0],
+ timeout=_NORMAL_TIMEOUT,
+ )
+ ad_service_receiver.ad.log.info('expectData 2nd %s' % expect_data)
+ check_discovered_dns_sd_txt_record(
+ ad_service_receiver,
+ expected_records=expect_data,
+ expected_src_device_address=(
+ ad_service_provider.p2p_device.device_address
+ ),
+ channel_id=ad_service_receiver.channel_ids[0],
+ timeout=_NORMAL_TIMEOUT,
+ )
+ got_all_expects = _check_all_expect_data(expect_data)
+ ad_service_receiver.ad.log.info(
+ 'Got all the expect data : %s', got_all_expects
+ )
+ asserts.assert_true(
+ got_all_expects,
+ "Don't got all the expect data.",
+ )
+ elif (
+ service_type == WifiP2PEnums.WifiP2pServiceInfo.WIFI_P2P_SERVICE_TYPE_UPNP
+ ):
+ ad_service_receiver.ad.log.info(
+ 'Request upnp service in %s with Query String %s '
+ % (ad_service_receiver.ad.serial, query_string1)
+ )
+ ad_service_receiver.ad.log.info('expectData %s' % expect_data)
+ if query_string1:
+ service_id = ad_service_receiver.ad.wifi.wifiP2pAddUpnpServiceRequest(
+ query_string1
+ )
+ else:
+ service_id = ad_service_receiver.ad.wifi.wifiP2pAddServiceRequest(
+ service_type
+ )
+ p2p_utils.set_upnp_response_listener(ad_service_receiver)
+ ad_service_receiver.ad.wifi.wifiP2pDiscoverServices()
+ ad_service_receiver.ad.log.info('Check Service Listener')
+ time.sleep(_DEFAULT_FUNCTION_SWITCH_TIME)
+ p2p_utils.check_discovered_services(
+ ad_service_receiver,
+ ad_service_provider.p2p_device.device_address,
+ expected_dns_sd_sequence=None,
+ expected_dns_txt_sequence=None,
+ expected_upnp_sequence=expect_data,
+ )
+ ad_service_receiver.ad.wifi.wifiP2pRemoveServiceRequest(service_id)
+ return 0
+
+
+def request_service_and_check_result_with_retry(
+ ad_service_provider,
+ ad_service_receiver,
+ service_type,
+ query_string1,
+ query_string2,
+ retry_count=3,
+):
+ """allow failures for requestServiceAndCheckResult.
+
+ Service
+
+ discovery might fail unexpectedly because the request packet might not be
+ received by the service responder due to p2p state switch.
+
+ Args:
+ ad_service_provider: The android device which provide p2p local service
+ ad_service_receiver: The android device which query p2p local service
+ service_type: P2p local service type, Upnp or Bonjour
+ query_string1: Query String, NonNull
+ query_string2: Query String, used for Bonjour, Nullable
+ retry_count: maximum retry count, default is 3
+ """
+ ret = 0
+ while retry_count > 0:
+ ret = request_service_and_check_result(
+ ad_service_provider,
+ ad_service_receiver,
+ service_type,
+ query_string1,
+ query_string2,
+ )
+ if ret == 0:
+ break
+ retry_count -= 1
+
+ asserts.assert_equal(0, ret, 'cannot find any services with retries.')
+
+
+def _check_no_discovered_service(
+ ad: android_device.AndroidDevice,
+ callback_handler: callback_handler_v2.CallbackHandlerV2,
+ event_name: str,
+ expected_src_device_address: str,
+ timeout: datetime.timedelta = _DEFAULT_TIMEOUT,
+):
+ """Checks that no service is received from the specified source device."""
+ def _is_expected_event(event):
+ src_device = constants.WifiP2pDevice.from_dict(
+ event.data['sourceDevice']
+ )
+ return src_device.device_address == expected_src_device_address
+
+ # Set to a small timeout to allow pulling all received events
+ if timeout.total_seconds() <= 1:
+ timeout = datetime.timedelta(seconds=1)
+ try:
+ event = callback_handler.waitForEvent(
+ event_name=event_name,
+ predicate=_is_expected_event,
+ timeout=timeout.total_seconds(),
+ )
+ except errors.CallbackHandlerTimeoutError:
+ # Timeout error is expected as there should not be any qualified service
+ return
+ asserts.assert_is_none(
+ event,
+ f'{ad} should not discover p2p service. Discovered: {event}',
+ )
+
+
+def check_discovered_dns_sd_response(
+ device: p2p_utils.DeviceState,
+ expected_responses: Sequence[Sequence[str, str]],
+ expected_src_device_address: str,
+ channel_id: int | None = None,
+ timeout: datetime.timedelta = _DEFAULT_TIMEOUT,
+):
+ """Check discovered DNS SD responses.
+
+ If no responses are expected, check that no DNS SD response appear within
+ timeout. Otherwise, wait for all expected responses within timeout.
+
+ This assumes that Bonjour service listener is set by
+ `set_dns_sd_response_listeners`.
+
+ Args:
+ device: The device that is discovering DNS SD responses.
+ expected_responses: The expected DNS SD responses.
+ expected_src_device_address: This only checks services that are from the
+ expected source device.
+ channel_id: The channel to check for expected responses.
+ timeout: The wait timeout.
+ """
+ channel_id = channel_id or device.channel_ids[0]
+ callback_handler = device.dns_sd_response_listeners[channel_id]
+
+ def _all_service_received(event):
+ nonlocal expected_responses
+ src_device = constants.WifiP2pDevice.from_dict(
+ event.data['sourceDevice']
+ )
+ if src_device.device_address != expected_src_device_address:
+ return False
+ registration_type = event.data['registrationType']
+ instance_name = event.data['instanceName']
+ service_item = instance_name + registration_type
+ device.ad.log.info('Received DNS SD response: %s', service_item)
+ if service_item in expected_responses:
+ expected_responses[service_item] = 0
+ _check_all_expect_data(expected_responses)
+
+ device.ad.log.info('Waiting for DNS SD services: %s', expected_responses)
+ # Set to a small timeout to allow pulling all received events
+ if timeout.total_seconds() <= 1:
+ timeout = datetime.timedelta(seconds=1)
+ try:
+ callback_handler.waitForEvent(
+ event_name=constants.ON_DNS_SD_SERVICE_AVAILABLE,
+ predicate=_all_service_received,
+ timeout=timeout.total_seconds(),
+ )
+ except errors.CallbackHandlerTimeoutError:
+ device.ad.log.info(f'need to wait for services: {expected_responses}')
+
+
+def check_discovered_dns_sd_txt_record(
+ device: p2p_utils.DeviceState,
+ expected_records: Sequence[Sequence[str, dict[str, str]]],
+ expected_src_device_address: str,
+ channel_id: int | None = None,
+ timeout: datetime.timedelta = _DEFAULT_TIMEOUT,
+):
+ """Check discovered DNS SD TXT records.
+
+ If no records are expected, check that no DNS SD TXT record appear within
+ timeout. Otherwise, wait for all expected records within timeout.
+
+ This assumes that Bonjour service listener is set by
+ `set_dns_sd_response_listeners`.
+
+ Args:
+ device: The device that is discovering DNS SD TXT records.
+ expected_records: The expected DNS SD TXT records.
+ expected_src_device_address: This only checks services that are from the
+ expected source device.
+ channel_id: The channel to check for expected records.
+ timeout: The wait timeout.
+ """
+ channel_id = channel_id or device.channel_ids[0]
+ idx = device.channel_ids.index(channel_id)
+ callback_handler = device.dns_sd_response_listeners[idx]
+
+ device.ad.log.info('Expected DNS SD TXT records: %s', expected_records)
+ def _all_service_received(event):
+ nonlocal expected_records
+ src_device = constants.WifiP2pDevice.from_dict(
+ event.data['sourceDevice']
+ )
+ if src_device.device_address != expected_src_device_address:
+ return False
+ full_domain_name = event.data['fullDomainName']
+ txt_record_map = event.data['txtRecordMap']
+ record_to_remove = full_domain_name + str(txt_record_map)
+ device.ad.log.info('Received DNS SD TXT record: %s', record_to_remove)
+ if record_to_remove in expected_records:
+ expected_records[record_to_remove] = 0
+ _check_all_expect_data(expected_records)
+
+ device.ad.log.info('Waiting for DNS SD TXT records: %s', expected_records)
+ # Set to a small timeout to allow pulling all received events
+ if timeout.total_seconds() <= 1:
+ timeout = datetime.timedelta(seconds=1)
+ try:
+ callback_handler.waitForEvent(
+ event_name=constants.ON_DNS_SD_TXT_RECORD_AVAILABLE,
+ predicate=_all_service_received,
+ timeout=timeout.total_seconds(),
+ )
+ except errors.CallbackHandlerTimeoutError:
+ device.ad.log.info(f'need to wait for services: {expected_records}')
+
+
class WifiP2PEnums:
"""Enums for WifiP2p."""
@@ -205,17 +737,17 @@ class WifiP2PEnums:
WIFI_P2P_SERVICE_TYPE_VENDOR_SPECIFIC = 255
class WifiP2pDnsSdServiceResponse:
- InstanceName = ''
- RegistrationType = ''
- FullDomainName = ''
- TxtRecordMap = {}
+ instance_name = ''
+ registration_type = ''
+ full_domain_name = ''
+ txt_record_map = {}
def __init__(self):
pass
- def toString(self):
+ def to_string(self):
return (
- self.InstanceName
- + self.RegistrationType
- + (self.FullDomainName + str(self.TxtRecordMap))
+ self.instance_name
+ + self.registration_type
+ + (self.full_domain_name + str(self.txt_record_map))
)
diff --git a/tests/hostsidetests/multidevices/test/direct/integration/wifi_p2p_manager_test.py b/tests/hostsidetests/multidevices/test/direct/integration/wifi_p2p_manager_test.py
new file mode 100644
index 0000000000..d4d6dab7f8
--- /dev/null
+++ b/tests/hostsidetests/multidevices/test/direct/integration/wifi_p2p_manager_test.py
@@ -0,0 +1,256 @@
+# 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.
+#
+# 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.
+
+# Lint as: python3
+"""ACTS Wifi P2pManager Test reimplemented in Mobly."""
+
+from collections.abc import Sequence
+import datetime
+import logging
+import time
+
+from android.platform.test.annotations import ApiTest
+from direct import constants
+from direct import p2p_utils
+from mobly import base_test
+from mobly import records
+from mobly import test_runner
+from mobly import utils
+from mobly.controllers import android_device
+import wifi_p2p_lib as wp2putils
+
+
+_DEFAULT_TIMEOUT = datetime.timedelta(seconds=30)
+DEFAULT_SLEEPTIME = 5
+_DEFAULT_FUNCTION_SWITCH_TIME = 10
+_DEFAULT_GROUP_CLIENT_LOST_TIME = 60
+
+_WIFI_DIRECT_SNIPPET_KEY = 'wifi_direct_mobly_snippet'
+
+P2P_CONNECT_NEGOTIATION = 0
+P2P_CONNECT_JOIN = 1
+P2P_CONNECT_INVITATION = 2
+
+WPS_PBC = wp2putils.WifiP2PEnums.WpsInfo.WIFI_WPS_INFO_PBC
+WPS_DISPLAY = wp2putils.WifiP2PEnums.WpsInfo.WIFI_WPS_INFO_DISPLAY
+WPS_KEYPAD = wp2putils.WifiP2PEnums.WpsInfo.WIFI_WPS_INFO_KEYPAD
+
+
+class WifiP2pManagerTest(base_test.BaseTestClass):
+ """Tests Wi-Fi Direct between 2 Android devices."""
+
+ ads: Sequence[android_device.AndroidDevice]
+ group_owner_ad: android_device.AndroidDevice
+ client_ad: android_device.AndroidDevice
+ network_name = 'DIRECT-xy-Hello'
+ passphrase = 'P2pWorld1234'
+ group_band = '2'
+
+ def setup_class(self) -> None:
+ super().setup_class()
+ self.ads = self.register_controller(android_device, min_number=2)
+ utils.concurrent_exec(
+ self._setup_device,
+ param_list=[[ad] for ad in self.ads],
+ raise_on_exception=True,
+ )
+ self.group_owner_ad, self.client_ad, *_ = self.ads
+ self.group_owner_ad.debug_tag = (
+ f'{self.group_owner_ad.serial}(Group Owner)'
+ )
+ self.client_ad.debug_tag = f'{self.client_ad.serial}(Client)'
+
+ def _setup_device(self, ad: android_device.AndroidDevice) -> None:
+ ad.load_snippet('wifi', constants.WIFI_SNIPPET_PACKAGE_NAME)
+ # Clear all saved Wi-Fi networks.
+ ad.wifi.wifiDisable()
+ ad.wifi.wifiClearConfiguredNetworks()
+ ad.wifi.wifiEnable()
+
+ def _teardown_wifi_p2p(self, ad: android_device.AndroidDevice):
+ try:
+ p2p_utils.teardown_wifi_p2p(ad)
+ finally:
+ ad.services.create_output_excerpts_all(self.current_test_info)
+
+ def teardown_test(self) -> None:
+ utils.concurrent_exec(
+ self._teardown_wifi_p2p,
+ param_list=[[ad] for ad in self.ads],
+ raise_on_exception=True,
+ )
+
+ def on_fail(self, record: records.TestResult) -> None:
+ logging.info('Collecting bugreports...')
+ android_device.take_bug_reports(
+ self.ads, destination=self.current_test_info.output_path
+ )
+
+ @ApiTest(
+ apis=[
+ 'android.net.wifi.p2p.WifiP2pManager#discoverPeers(android.net.wifi.p2p.WifiP2pManager.Channel channel, android.net.wifi.p2p.WifiP2pManager.ActionListener listener)',
+ ]
+ )
+ def test_p2p_discovery(self):
+ """Verify the p2p discovery functionality.
+
+ Steps:
+ 1. Discover the target device
+ 2. Check the target device in peer list
+ """
+ self.ads[0].log.info('Device discovery')
+ responder = p2p_utils.setup_wifi_p2p(self.ads[0])
+ requester = p2p_utils.setup_wifi_p2p(self.ads[1])
+
+ requester.ad.log.info('Searching for target device.')
+ responder_p2p_dev = p2p_utils.discover_p2p_peer(responder, requester)
+ self.ads[0].log.info('name= %s, address=%s, group_owner=%s',
+ responder_p2p_dev.device_name,
+ responder_p2p_dev.device_address,
+ responder_p2p_dev.is_group_owner)
+ requester_p2p_dev = p2p_utils.discover_p2p_peer(requester, responder)
+ self.ads[1].log.info('name= %s, address=%s, group_owner=%s',
+ requester_p2p_dev.device_name,
+ requester_p2p_dev.device_address,
+ requester_p2p_dev.is_group_owner)
+
+ @ApiTest(
+ apis=[
+ 'android.net.wifi.p2p.WifiP2pManager#requestConnectionInfo(android.net.wifi.p2p.WifiP2pManager.Channel channel, android.net.wifi.p2p.WifiP2pManager.ConnectionInfoListener listener)',
+ 'android.net.wifi.p2p.WifiP2pManager#connect(android.net.wifi.p2p.WifiP2pManager.Channel channel, android.net.wifi.p2p.WifiP2pConfig config, android.net.wifi.p2p.WifiP2pManager.ActionListener listener)',
+ ]
+ )
+ def test_p2p_connect_via_pbc_and_ping_and_reconnect(self):
+ """Verify the p2p connect via pbc functionality.
+
+ Steps:
+ 1. Request the connection which include discover the target device
+ 2. check which dut is GO and which dut is GC
+ 3. connection check via ping from GC to GO
+ 4. disconnect
+ 5. Trigger connect again from GO for reconnect test.
+ 6. GO trigger disconnect
+ 7. Trigger connect again from GC for reconnect test.
+ 8. GC trigger disconnect
+ """
+ self.ads[0].log.info('Device initialize')
+ go_dut = self.ads[0]
+ gc_dut = self.ads[1]
+
+ logging.info('GO: %s, GC: %s', go_dut.serial, gc_dut.serial)
+ device_go = p2p_utils.setup_wifi_p2p(go_dut)
+ device_gc = p2p_utils.setup_wifi_p2p(gc_dut)
+ self.run_p2p_connect_and_ping(device_gc, device_go, WPS_PBC, False)
+ self.run_p2p_connect_and_ping(device_go, device_gc, WPS_PBC, True)
+ self.run_p2p_connect_and_ping(device_gc, device_go, WPS_PBC, True)
+
+ @ApiTest(
+ apis=[
+ 'android.net.wifi.p2p.WifiP2pManager#requestConnectionInfo(android.net.wifi.p2p.WifiP2pManager.Channel channel, android.net.wifi.p2p.WifiP2pManager.ConnectionInfoListener listener)',
+ 'android.net.wifi.p2p.WifiP2pManager#connect(android.net.wifi.p2p.WifiP2pManager.Channel channel, android.net.wifi.p2p.WifiP2pConfig config, android.net.wifi.p2p.WifiP2pManager.ActionListener listener)',
+ ]
+ )
+ def test_p2p_connect_via_display_and_ping_and_reconnect(self):
+ """Verify the p2p connect via display functionality.
+
+ Steps:
+ 1. Request the connection which include discover the target device
+ 2. check which dut is GO and which dut is GC
+ 3. connection check via ping from GC to GO
+ 4. disconnect
+ 5. Trigger connect again from GO for reconnect test.
+ 6. GO trigger disconnect
+ 7. Trigger connect again from GC for reconnect test.
+ 8. GC trigger disconnect
+ """
+ self.ads[0].log.info('Device initialize')
+ go_dut = self.ads[0]
+ gc_dut = self.ads[1]
+
+ logging.info('GO: %s, GC: %s', go_dut.serial, gc_dut.serial)
+ device_go = p2p_utils.setup_wifi_p2p(go_dut)
+ device_gc = p2p_utils.setup_wifi_p2p(gc_dut)
+ self.run_p2p_connect_and_ping(device_gc, device_go, WPS_DISPLAY, False)
+ self.run_p2p_connect_and_ping(device_go, device_gc, WPS_DISPLAY, True)
+ self.run_p2p_connect_and_ping(device_gc, device_go, WPS_DISPLAY, True)
+
+ @ApiTest(
+ apis=[
+ 'android.net.wifi.p2p.WifiP2pManager#requestConnectionInfo(android.net.wifi.p2p.WifiP2pManager.Channel channel, android.net.wifi.p2p.WifiP2pManager.ConnectionInfoListener listener)',
+ 'android.net.wifi.p2p.WifiP2pManager#connect(android.net.wifi.p2p.WifiP2pManager.Channel channel, android.net.wifi.p2p.WifiP2pConfig config, android.net.wifi.p2p.WifiP2pManager.ActionListener listener)',
+ ]
+ )
+ def test_p2p_connect_via_keypad_and_ping_and_reconnect(self):
+ """Verify the p2p connect via keypad functionality.
+
+ Steps:
+ 1. Request the connection which include discover the target device
+ 2. check which dut is GO and which dut is GC
+ 3. connection check via ping from GC to GO
+ 4. disconnect
+ 5. Trigger connect again from GO for reconnect test.
+ 6. GO trigger disconnect
+ 7. Trigger connect again from GC for reconnect test.
+ 8. GC trigger disconnect
+ """
+ self.ads[0].log.info('Device initialize')
+ go_dut = self.ads[0]
+ gc_dut = self.ads[1]
+
+ logging.info('GO: %s, GC: %s', go_dut.serial, gc_dut.serial)
+ device_go = p2p_utils.setup_wifi_p2p(go_dut)
+ device_gc = p2p_utils.setup_wifi_p2p(gc_dut)
+
+ self.run_p2p_connect_and_ping(device_gc, device_go, WPS_KEYPAD, False)
+ self.run_p2p_connect_and_ping(device_go, device_gc, WPS_KEYPAD, True)
+ self.run_p2p_connect_and_ping(device_gc, device_go, WPS_KEYPAD, True)
+
+ def run_p2p_connect_and_ping(
+ self,
+ device1,
+ device2,
+ pws_method,
+ re_connect):
+ # Request the connection
+ wp2putils.p2p_connect(device1, device2, re_connect, pws_method)
+
+ if wp2putils.is_go(device1.ad):
+ client_dut = device2.ad
+ else:
+ client_dut = device1.ad
+ logging.info('Client is : %s', client_dut.serial)
+ go_ip = wp2putils.p2p_go_ip(client_dut)
+ wp2putils.p2p_connection_ping_test(client_dut, go_ip)
+
+ # trigger disconnect
+ p2p_utils.remove_group_and_verify_disconnected(
+ device1, device2, is_group_negotiation=False
+ )
+ time.sleep(_DEFAULT_FUNCTION_SWITCH_TIME)
+
+if __name__ == '__main__':
+ test_runner.main()
+
diff --git a/tests/hostsidetests/multidevices/test/direct/p2p_utils.py b/tests/hostsidetests/multidevices/test/direct/p2p_utils.py
index 45ff6d7c74..06584a0142 100644
--- a/tests/hostsidetests/multidevices/test/direct/p2p_utils.py
+++ b/tests/hostsidetests/multidevices/test/direct/p2p_utils.py
@@ -17,6 +17,7 @@ from collections.abc import Sequence
import dataclasses
import datetime
import logging
+import time
from mobly import asserts
from mobly.snippet import errors
@@ -332,17 +333,29 @@ def p2p_connect(
requester.ad.log.info('Sent P2P connect invitation to responder.')
# Connect with WPS config requires user inetraction through UI.
if config.wps_setup == constants.WpsInfo.PBC:
+ time.sleep(_DEFAULT_UI_RESPONSE_TIME.total_seconds())
responder.ad.wifi.wifiP2pAcceptInvitation(
requester.p2p_device.device_name
)
responder.ad.log.info('Accepted connect invitation.')
elif config.wps_setup == constants.WpsInfo.DISPLAY:
+ time.sleep(_DEFAULT_UI_RESPONSE_TIME.total_seconds())
pin = requester.ad.wifi.wifiP2pGetPinCode(
responder.p2p_device.device_name
)
requester.ad.log.info('p2p connection PIN code: %s', pin)
+ time.sleep(_DEFAULT_UI_RESPONSE_TIME.total_seconds())
responder.ad.wifi.wifiP2pEnterPin(pin, requester.p2p_device.device_name)
responder.ad.log.info('Enetered PIN code.')
+ elif config.wps_setup == constants.WpsInfo.KEYPAD:
+ time.sleep(_DEFAULT_UI_RESPONSE_TIME.total_seconds())
+ pin = responder.ad.wifi.wifiP2pGetKeypadPinCode(
+ requester.p2p_device.device_name
+ )
+ responder.ad.log.info('p2p connection Keypad PIN code: %s', pin)
+ time.sleep(_DEFAULT_UI_RESPONSE_TIME.total_seconds())
+ requester.ad.wifi.wifiP2pEnterPin(pin, responder.p2p_device.device_name)
+ requester.ad.log.info('Enetered Keypad PIN code.')
elif config.wps_setup is not None:
asserts.fail(f'Unsupported WPS configuration: {config.wps_setup}')
@@ -370,6 +383,59 @@ def p2p_connect(
logging.info('Established wifi p2p connection.')
+def p2p_reconnect(
+ requester: DeviceState,
+ responder: DeviceState,
+ config: constants.WifiP2pConfig,
+) -> None:
+ """Establishes Wi-Fi p2p connection with WPS configuration.
+
+ This method instructs the requester to initiate a connection request and the
+ responder to accept the connection. It then verifies the connection status
+ on both devices.
+
+ Args:
+ requester: The requester device.
+ responder: The responder device.
+ config: The Wi-Fi p2p configuration.
+ """
+ logging.info(
+ 'Establishing a p2p connection through p2p configuration %s.', config
+ )
+
+ # Clear events in broadcast receiver.
+ _clear_events(requester, constants.WIFI_P2P_PEERS_CHANGED_ACTION)
+ _clear_events(requester, constants.WIFI_P2P_CONNECTION_CHANGED_ACTION)
+ _clear_events(responder, constants.WIFI_P2P_PEERS_CHANGED_ACTION)
+ _clear_events(responder, constants.WIFI_P2P_CONNECTION_CHANGED_ACTION)
+
+ requester.ad.wifi.wifiP2pConnect(config.to_dict())
+ requester.ad.log.info('Sent P2P connect invitation to responder.')
+
+ # Check p2p status on requester.
+ _wait_connection_notice(requester.broadcast_receiver)
+ _wait_peer_connected(
+ requester.broadcast_receiver,
+ responder.p2p_device.device_address,
+ )
+ requester.ad.log.info(
+ 'Connected with device %s through wifi p2p.',
+ responder.p2p_device.device_address,
+ )
+
+ # Check p2p status on responder.
+ _wait_connection_notice(responder.broadcast_receiver)
+ _wait_peer_connected(
+ responder.broadcast_receiver,
+ requester.p2p_device.device_address,
+ )
+ responder.ad.log.info(
+ 'Connected with device %s through wifi p2p.',
+ requester.p2p_device.device_address,
+ )
+ logging.info('Established wifi p2p connection.')
+
+
def _wait_peer_connected(
broadcast_receiver: callback_handler_v2.CallbackHandlerV2, peer_address: str
):
diff --git a/tests/hostsidetests/multidevices/test/direct/cts_wifi_direct_test_suite.py b/tests/hostsidetests/multidevices/test/direct/wifi_direct_test_suite.py
index 80d12abe05..6598e39648 100644
--- a/tests/hostsidetests/multidevices/test/direct/cts_wifi_direct_test_suite.py
+++ b/tests/hostsidetests/multidevices/test/direct/wifi_direct_test_suite.py
@@ -13,7 +13,7 @@
# limitations under the License.
# Lint as: python3
-"""CTS Wi-Fi Direct test suite."""
+"""Wi-Fi Direct test suite."""
from mobly import base_suite
from mobly import suite_runner
@@ -24,8 +24,8 @@ from direct import group_owner_with_config_test
from direct import service_discovery_test
-class CtsWifiDirectTestSuite(base_suite.BaseSuite):
- """CTS Wi-Fi Direct test suite."""
+class WifiDirectTestSuite(base_suite.BaseSuite):
+ """Wi-Fi Direct test suite."""
def setup_suite(self, config):
del config # unused
diff --git a/tests/hostsidetests/multidevices/test/softap/AndroidTest.xml b/tests/hostsidetests/multidevices/test/softap/AndroidTest.xml
index 19da4cca39..26ddcdd877 100644
--- a/tests/hostsidetests/multidevices/test/softap/AndroidTest.xml
+++ b/tests/hostsidetests/multidevices/test/softap/AndroidTest.xml
@@ -21,18 +21,12 @@
<target_preparer class="AndroidDeviceFeaturesCheckDecorator">
<option name="required_feature" value="android.hardware.wifi" />
</target_preparer>
- <target_preparer class="AndroidMainlineModulesCheckDecorator">
- <option name="mainline_module_package_name" value="com.google.android.wifi" />
- </target_preparer>
<target_preparer class="AndroidInstallAppsDecorator" />
</device>
<device name="AndroidDevice">
<target_preparer class="AndroidDeviceFeaturesCheckDecorator">
<option name="required_feature" value="android.hardware.wifi" />
</target_preparer>
- <target_preparer class="AndroidMainlineModulesCheckDecorator">
- <option name="mainline_module_package_name" value="com.google.android.wifi" />
- </target_preparer>
<target_preparer class="AndroidInstallAppsDecorator" />
</device>