Merge "Add WiFi Aware ApiTest description for the following cases." into main
diff --git a/tests/OWNERS b/tests/OWNERS
index bde7824..288dd24 100644
--- a/tests/OWNERS
+++ b/tests/OWNERS
@@ -4,4 +4,3 @@
 # Engprod - Not owner of the test but help maintaining the module as an example
 [email protected]
 [email protected]
[email protected]
diff --git a/tests/hostsidetests/multidevices/com.google.snippet.wifi/aware/Android.bp b/tests/hostsidetests/multidevices/com.google.snippet.wifi/aware/Android.bp
index 09249b5..c0edd52 100644
--- a/tests/hostsidetests/multidevices/com.google.snippet.wifi/aware/Android.bp
+++ b/tests/hostsidetests/multidevices/com.google.snippet.wifi/aware/Android.bp
@@ -53,6 +53,7 @@
         "compatibility-device-util-axt",
         "guava",
         "mobly-snippet-lib",
+        "mobly-bundled-snippets-lib",
     ],
     min_sdk_version: "31",
 }
diff --git a/tests/hostsidetests/multidevices/com.google.snippet.wifi/aware/AndroidManifestNew.xml b/tests/hostsidetests/multidevices/com.google.snippet.wifi/aware/AndroidManifestNew.xml
index 7dc04df..cf13a13 100644
--- a/tests/hostsidetests/multidevices/com.google.snippet.wifi/aware/AndroidManifestNew.xml
+++ b/tests/hostsidetests/multidevices/com.google.snippet.wifi/aware/AndroidManifestNew.xml
@@ -1,6 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <manifest
         xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:tools="http://schemas.android.com/tools"
         package="com.google.snippet.wifi.aware">
     <!-- Declare the minimum Android SDK version and internet permission,
          which are required by Mobly Snippet Lib since it uses network socket. -->
@@ -20,8 +21,10 @@
              of a snippet class -->
         <meta-data
                 android:name="mobly-snippets"
+                tools:replace="android:value"
                 android:value="com.google.snippet.wifi.aware.WifiAwareManagerSnippet,
-                       com.google.snippet.wifi.aware.ConnectivityManagerSnippet,"/>
+                       com.google.snippet.wifi.aware.ConnectivityManagerSnippet,
+                       com.google.android.mobly.snippet.bundled.WifiManagerSnippet"/>
         <meta-data
                 android:name="mobly-object-converter"
                 android:value="com.google.snippet.wifi.aware.WifiAwareSnippetConverter"/>
diff --git a/tests/hostsidetests/multidevices/com.google.snippet.wifi/aware/WifiAwareJsonDeserializer.java b/tests/hostsidetests/multidevices/com.google.snippet.wifi/aware/WifiAwareJsonDeserializer.java
index 7c4eb88..70a0a63 100644
--- a/tests/hostsidetests/multidevices/com.google.snippet.wifi/aware/WifiAwareJsonDeserializer.java
+++ b/tests/hostsidetests/multidevices/com.google.snippet.wifi/aware/WifiAwareJsonDeserializer.java
@@ -96,7 +96,6 @@
     private static final String RANGING_REQUEST_PEER_IDS = "peer_ids";
     private static final String RANGING_REQUEST_PEER_MACS = "peer_mac_addresses";
 
-
     private WifiAwareJsonDeserializer() {
     }
 
diff --git a/tests/hostsidetests/multidevices/com.google.snippet.wifi/aware/WifiAwareManagerSnippet.java b/tests/hostsidetests/multidevices/com.google.snippet.wifi/aware/WifiAwareManagerSnippet.java
index f7d8673..3cf9fff 100644
--- a/tests/hostsidetests/multidevices/com.google.snippet.wifi/aware/WifiAwareManagerSnippet.java
+++ b/tests/hostsidetests/multidevices/com.google.snippet.wifi/aware/WifiAwareManagerSnippet.java
@@ -43,6 +43,7 @@
 import android.net.wifi.rtt.RangingResult;
 import android.net.wifi.rtt.RangingResultCallback;
 import android.net.wifi.rtt.WifiRttManager;
+import android.net.wifi.ScanResult;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
 import android.os.Bundle;
@@ -65,11 +66,15 @@
 import com.google.android.mobly.snippet.rpc.RpcOptional;
 import com.google.android.mobly.snippet.util.Log;
 
+import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
 
 import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
+import java.util.ListIterator;
 import java.util.concurrent.ConcurrentHashMap;
 
 /**
@@ -347,6 +352,10 @@
     /**
      * Checks if Wi-Fi RTT is available.
      */
+    @Rpc(description = "Check if Wi-Fi Aware is available")
+    public Boolean wifiRttIsAvailable() {
+        return mWifiRttManager.isAvailable();
+    }
     private void checkWifiRttAvailable() throws WifiAwareManagerSnippetException {
         if (!mWifiRttManager.isAvailable()) {
             throw new WifiAwareManagerSnippetException("WiFi RTT is not available now.");
@@ -833,6 +842,98 @@
     }
 
     /**
+     * Converts a JSON representation of a ScanResult to an actual ScanResult object. Mirror of
+     * the code in
+     * {@link com.googlecode.android_scripting.jsonrpc.JsonBuilder#buildJsonScanResult(ScanResult)}.
+     *
+     * @param j JSON object representing a ScanResult.
+     * @return a ScanResult object
+     * @throws JSONException on any JSON errors
+     */
+    public static ScanResult getScanResult(JSONObject j) throws JSONException {
+        if (j == null) {
+            return null;
+        }
+
+        ScanResult scanResult = new ScanResult();
+
+        if (j.has("BSSID")) {
+            scanResult.BSSID = j.getString("BSSID");
+        }
+        if (j.has("SSID")) {
+            scanResult.SSID = j.getString("SSID");
+        }
+        if (j.has("frequency")) {
+            scanResult.frequency = j.getInt("frequency");
+        }
+        if (j.has("level")) {
+            scanResult.level = j.getInt("level");
+        }
+        if (j.has("capabilities")) {
+            scanResult.capabilities = j.getString("capabilities");
+        }
+        if (j.has("timestamp")) {
+            scanResult.timestamp = j.getLong("timestamp");
+        }
+        if (j.has("centerFreq0")) {
+            scanResult.centerFreq0 = j.getInt("centerFreq0");
+        }
+        if (j.has("centerFreq1")) {
+            scanResult.centerFreq1 = j.getInt("centerFreq1");
+        }
+        if (j.has("channelWidth")) {
+            scanResult.channelWidth = j.getInt("channelWidth");
+        }
+        if (j.has("operatorFriendlyName")) {
+            scanResult.operatorFriendlyName = j.getString("operatorFriendlyName");
+        }
+        if (j.has("venueName")) {
+            scanResult.venueName = j.getString("venueName");
+        }
+
+        return scanResult;
+    }
+
+    /**
+     * Converts a JSONArray toa a list of ScanResult.
+     *
+     * @param j JSONArray representing a collection of ScanResult objects
+     * @return a list of ScanResult objects
+     * @throws JSONException on any JSON error
+     */
+    public static List<ScanResult> getScanResults(JSONArray j) throws JSONException {
+        if (j == null || j.length() == 0) {
+            return null;
+        }
+
+        ArrayList<ScanResult> scanResults = new ArrayList<>(j.length());
+        for (int i = 0; i < j.length(); ++i) {
+            scanResults.add(getScanResult(j.getJSONObject(i)));
+        }
+
+        return scanResults;
+    }
+
+    /**
+     * Starts Wi-Fi RTT ranging with Wi-Fi Aware access points.
+     *
+     * @param callbackId        Assigned automatically by mobly for all async RPCs.
+     * @param requestJsonObject The ranging request in JSONArray type for calling {@link
+     *                          android.net.wifi.ScanResult}.
+     */
+    @AsyncRpc(description = "Start ranging to an Access Points.")
+    public void wifiRttStartRangingToAccessPoints(
+            String callbackId, JSONArray requestJsonObject
+    ) throws JSONException, WifiAwareManagerSnippetException {
+        Log.v("wifiRttStartRangingToAccessPoints: " + requestJsonObject);
+        RangingRequest request = new RangingRequest.Builder().addAccessPoints(
+                            getScanResults(requestJsonObject)).build();
+        Log.v("Starting Wi-Fi RTT ranging with access point: " + request.toString());
+        RangingCallback rangingCb = new RangingCallback(eventCache, callbackId);
+        mWifiRttManager.startRanging(request, command -> mHandler.post(command), rangingCb);
+    }
+
+    /**
      * Starts Wi-Fi RTT ranging with Wi-Fi Aware peers.
      *
      * @param callbackId        Assigned automatically by mobly for all async RPCs.
@@ -869,7 +970,7 @@
         public void onRangingFailure(int code) {
             SnippetEvent event = new SnippetEvent(mCallbackId, EVENT_NAME_RANGING_RESULT);
             event.getData().putString("callbackName", "onRangingFailure");
-            event.getData().putInt("statusCode", code);
+            event.getData().putInt("status", code);
             mEventCache.postEvent(event);
         }
 
diff --git a/tests/hostsidetests/multidevices/com.google.snippet.wifi/aware/WifiAwareSnippetConverter.java b/tests/hostsidetests/multidevices/com.google.snippet.wifi/aware/WifiAwareSnippetConverter.java
index 154d0eb..edcfeac 100644
--- a/tests/hostsidetests/multidevices/com.google.snippet.wifi/aware/WifiAwareSnippetConverter.java
+++ b/tests/hostsidetests/multidevices/com.google.snippet.wifi/aware/WifiAwareSnippetConverter.java
@@ -19,14 +19,17 @@
 import android.net.NetworkRequest;
 import android.net.wifi.aware.PublishConfig;
 import android.net.wifi.aware.SubscribeConfig;
+import android.net.wifi.ScanResult;
 import android.net.wifi.aware.WifiAwareNetworkSpecifier;
 
 import com.google.android.mobly.snippet.SnippetObjectConverter;
+import com.google.android.mobly.snippet.util.Log;
 
 import org.json.JSONException;
 import org.json.JSONObject;
 
 import java.lang.reflect.Type;
+import java.util.List;
 
 /**
  * The converter class that allows users to use custom type as snippet RPC arguments and return
@@ -34,6 +37,19 @@
  */
 public class WifiAwareSnippetConverter implements SnippetObjectConverter {
 
+
+    public static String trimQuotationMarks(String originalString) {
+        String result = originalString;
+        if (originalString == null)
+            return result;
+        if (originalString.length() > 2
+                && originalString.charAt(0) == '"'
+                && originalString.charAt(originalString.length() - 1) == '"') {
+            result = originalString.substring(1, originalString.length() - 1);
+        }
+        return result;
+    }
+
     @Override
     public JSONObject serialize(Object object) throws JSONException {
         // If the RPC method requires a custom return type, e.g. SubscribeConfig, PublishConfig, we
@@ -49,6 +65,24 @@
         return null;
     }
 
+    public static JSONObject serializeScanResult(ScanResult data) throws JSONException {
+        JSONObject result = new JSONObject();
+        result.put("BSSID", data.BSSID);
+        result.put("SSID", trimQuotationMarks(data.getWifiSsid().toString()));
+        result.put("capabilities", data.capabilities);
+        result.put("centerFreq0", data.centerFreq0);
+        result.put("centerFreq1", data.centerFreq1);
+        result.put("channelWidth", data.channelWidth);
+        result.put("frequency", data.frequency);
+        result.put("level", data.level);
+        result.put("operatorFriendlyName",
+            (data.operatorFriendlyName != null) ? data.operatorFriendlyName.toString() : "");
+        result.put("timestamp", data.timestamp);
+        result.put("venueName", (data.venueName != null) ? data.venueName.toString() : "");
+        result.put("scan_result_parcel", SerializationUtil.parcelableToString(data));
+        return result;
+    }
+
     @Override
     public Object deserialize(JSONObject jsonObject, Type type) throws JSONException {
         // The parameters of Mobly RPC directly reference the Object type.
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 ab5fa1c..78b58b3 100644
--- a/tests/hostsidetests/multidevices/com.google.snippet.wifi/direct/WifiP2pManagerSnippet.java
+++ b/tests/hostsidetests/multidevices/com.google.snippet.wifi/direct/WifiP2pManagerSnippet.java
@@ -205,6 +205,21 @@
     }
 
     /**
+     * Request the connection information in the form of WifiP2pDevice.
+     *
+     * @param callbackId The callback ID assigned by Mobly.
+     * @param channelId The ID of the channel for Wi-Fi P2P to operate on.
+     */
+    @AsyncRpc(description = "Request the connection information in the form of WifiP2pDevice.")
+    public void wifiP2pRequestConnectionInfo(String callbackId,
+            @RpcDefault(value = "0") Integer channelId)
+            throws WifiP2pManagerException {
+        WifiP2pManager.Channel channel = getChannel(channelId);
+        mP2pManager.requestConnectionInfo(channel,
+            new WifiP2pConnectionInfoListener(callbackId));
+    }
+
+    /**
      * Initiate peer discovery. A discovery process involves scanning for available Wi-Fi peers for
      * the purpose of establishing a connection.
      *
@@ -866,6 +881,27 @@
         }
     }
 
+    private static class  WifiP2pConnectionInfoListener
+        implements WifiP2pManager.ConnectionInfoListener {
+        public static final String EVENT_NAME_ON_CONNECTION_INFO =
+            "WifiP2pOnConnectionInfoAvailable";
+        private final String mCallbackId;
+
+        public WifiP2pConnectionInfoListener(String callbackId) {
+            this.mCallbackId = callbackId;
+        }
+
+        @Override
+        public void onConnectionInfoAvailable(WifiP2pInfo info) {
+            Log.d(TAG + ": onConnectionInfoAvailable: " + info.toString());
+            SnippetEvent event = new SnippetEvent(mCallbackId, EVENT_NAME_ON_CONNECTION_INFO);
+            event.getData().putBoolean("groupFormed", info.groupFormed);
+            event.getData().putBoolean("isGroupOwner", info.isGroupOwner);
+            event.getData().putString("groupOwnerHostAddress", info.groupOwnerAddress.toString());
+            EventCache.getInstance().postEvent(event);
+        }
+    }
+
     private static class DeviceInfoListener implements WifiP2pManager.DeviceInfoListener {
         public static final String EVENT_NAME_ON_DEVICE_INFO = "WifiP2pOnDeviceInfoAvailable";
 
diff --git a/tests/hostsidetests/multidevices/test/aware/integration/Android.bp b/tests/hostsidetests/multidevices/test/aware/integration/Android.bp
index 68c7666..55483e3 100644
--- a/tests/hostsidetests/multidevices/test/aware/integration/Android.bp
+++ b/tests/hostsidetests/multidevices/test/aware/integration/Android.bp
@@ -226,3 +226,22 @@
         tags: ["mobly"],
     },
 }
+
+python_test_host {
+    name: "WifiRttDisableTestCases",
+    main: "wifi_rtt_disable_test.py",
+    srcs: ["wifi_rtt_disable_test.py"],
+    device_common_data: [":wifi_aware_snippet_new"],
+    libs: [
+        "aware_lib_utils",
+        "mobly",
+        "wifi_aware_constants",
+    ],
+    test_suites: [
+        "general-tests",
+    ],
+    test_options: {
+        unit_test: false,
+        tags: ["mobly"],
+    },
+}
diff --git a/tests/hostsidetests/multidevices/test/aware/integration/wifi_aware_datapath_test.py b/tests/hostsidetests/multidevices/test/aware/integration/wifi_aware_datapath_test.py
index 21d26aa..6233347 100644
--- a/tests/hostsidetests/multidevices/test/aware/integration/wifi_aware_datapath_test.py
+++ b/tests/hostsidetests/multidevices/test/aware/integration/wifi_aware_datapath_test.py
@@ -1046,7 +1046,7 @@
             _DATA_PATH_INITIATOR,
             resp_mac,
             init_passphrase,
-            resp_pmk,
+            init_pmk,
             network_id
             )
         # Initiator & Responder:
@@ -1657,6 +1657,14 @@
     # peer using the Aware-provided peer handle (as opposed to a MAC address).
     #######################################
 
+    @ApiTest(
+    apis=[
+        'android.net.wifi.aware.PublishConfig.Builder#setPublishType(PublishConfig.PUBLISH_TYPE_UNSOLICITED)',
+        'android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType(SubscribeConfig.SUBSCRIBE_TYPE_PASSIVE)',
+        'android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build()',
+        ]
+    )
+
     def test_ib_unsolicited_passive_open_specific(self):
         """Data-path: in-band, unsolicited/passive, open encryption, specific peer
 
@@ -1668,6 +1676,14 @@
             encr_type=self.ENCR_TYPE_OPEN,
             use_peer_id=True)
 
+    @ApiTest(
+    apis=[
+        'android.net.wifi.aware.PublishConfig.Builder#setPublishType(PublishConfig.PUBLISH_TYPE_UNSOLICITED)',
+        'android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType(SubscribeConfig.SUBSCRIBE_TYPE_PASSIVE)',
+        'android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build()',
+        ]
+    )
+
     def test_ib_unsolicited_passive_open_any(self):
         """Data-path: in-band, unsolicited/passive, open encryption, any peer
 
@@ -1679,6 +1695,15 @@
             encr_type=self.ENCR_TYPE_OPEN,
             use_peer_id=False)
 
+    @ApiTest(
+    apis=[
+        'android.net.wifi.aware.PublishConfig.Builder#setPublishType(PublishConfig.PUBLISH_TYPE_UNSOLICITED)',
+        'android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType(SubscribeConfig.SUBSCRIBE_TYPE_PASSIVE)',
+        'android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build()',
+        'android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setPskPassphrase(String)',
+        ]
+    )
+
     def test_ib_unsolicited_passive_passphrase_specific(self):
         """Data-path: in-band, unsolicited/passive, passphrase, specific peer
 
@@ -1690,6 +1715,15 @@
             encr_type=self.ENCR_TYPE_PASSPHRASE,
             use_peer_id=True)
 
+    @ApiTest(
+    apis=[
+        'android.net.wifi.aware.PublishConfig.Builder#setPublishType(PublishConfig.PUBLISH_TYPE_UNSOLICITED)',
+        'android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType(SubscribeConfig.SUBSCRIBE_TYPE_PASSIVE)',
+        'android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build()',
+        'android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setPskPassphrase(String)',
+        ]
+    )
+
     def test_ib_unsolicited_passive_passphrase_any(self):
         """Data-path: in-band, unsolicited/passive, passphrase, any peer
 
@@ -1701,6 +1735,15 @@
             encr_type=self.ENCR_TYPE_PASSPHRASE,
             use_peer_id=False)
 
+    @ApiTest(
+    apis=[
+        'android.net.wifi.aware.PublishConfig.Builder#setPublishType(PublishConfig.PUBLISH_TYPE_UNSOLICITED)',
+        'android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType(SubscribeConfig.SUBSCRIBE_TYPE_PASSIVE)',
+        'android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build()',
+        'android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setPmk(byte[])',
+        ]
+    )
+
     def test_ib_unsolicited_passive_pmk_specific(self):
         """Data-path: in-band, unsolicited/passive, PMK, specific peer
 
@@ -1712,6 +1755,15 @@
             encr_type=self.ENCR_TYPE_PMK,
             use_peer_id=True)
 
+    @ApiTest(
+    apis=[
+        'android.net.wifi.aware.PublishConfig.Builder#setPublishType(PublishConfig.PUBLISH_TYPE_UNSOLICITED)',
+        'android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType(SubscribeConfig.SUBSCRIBE_TYPE_PASSIVE)',
+        'android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build()',
+        'android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setPmk(byte[])',
+        ]
+    )
+
     def test_ib_unsolicited_passive_pmk_any(self):
         """Data-path: in-band, unsolicited/passive, PMK, any peer
 
@@ -1723,6 +1775,14 @@
             encr_type=self.ENCR_TYPE_PMK,
             use_peer_id=False)
 
+    @ApiTest(
+    apis=[
+        'android.net.wifi.aware.PublishConfig.Builder#setPublishType(PublishConfig.PUBLISH_TYPE_SOLICITED)',
+        'android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType(SubscribeConfig.SUBSCRIBE_TYPE_ACTIVE)',
+        'android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build()',
+        ]
+    )
+
     def test_ib_solicited_active_open_specific(self):
         """Data-path: in-band, solicited/active, open encryption, specific peer
 
@@ -1734,6 +1794,14 @@
             encr_type=self.ENCR_TYPE_OPEN,
             use_peer_id=True)
 
+    @ApiTest(
+    apis=[
+        'android.net.wifi.aware.PublishConfig.Builder#setPublishType(PublishConfig.PUBLISH_TYPE_SOLICITED)',
+        'android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType(SubscribeConfig.SUBSCRIBE_TYPE_ACTIVE)',
+        'android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build()',
+        ]
+    )
+
     def test_ib_solicited_active_open_any(self):
         """Data-path: in-band, solicited/active, open encryption, any peer
 
@@ -1745,6 +1813,15 @@
             encr_type=self.ENCR_TYPE_OPEN,
             use_peer_id=False)
 
+    @ApiTest(
+    apis=[
+        'android.net.wifi.aware.PublishConfig.Builder#setPublishType(PublishConfig.PUBLISH_TYPE_SOLICITED)',
+        'android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType(SubscribeConfig.SUBSCRIBE_TYPE_ACTIVE)',
+        'android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build()',
+        'android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setPskPassphrase(String)',
+        ]
+    )
+
     def test_ib_solicited_active_passphrase_specific(self):
         """Data-path: in-band, solicited/active, passphrase, specific peer
 
@@ -1756,6 +1833,15 @@
             encr_type=self.ENCR_TYPE_PASSPHRASE,
             use_peer_id=True)
 
+    @ApiTest(
+    apis=[
+        'android.net.wifi.aware.PublishConfig.Builder#setPublishType(PublishConfig.PUBLISH_TYPE_SOLICITED)',
+        'android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType(SubscribeConfig.SUBSCRIBE_TYPE_ACTIVE)',
+        'android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build()',
+        'android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setPskPassphrase(String)',
+        ]
+    )
+
     def test_ib_solicited_active_passphrase_any(self):
         """Data-path: in-band, solicited/active, passphrase, any peer
 
@@ -1767,6 +1853,15 @@
             encr_type=self.ENCR_TYPE_PASSPHRASE,
             use_peer_id=False)
 
+    @ApiTest(
+    apis=[
+        'android.net.wifi.aware.PublishConfig.Builder#setPublishType(PublishConfig.PUBLISH_TYPE_SOLICITED)',
+        'android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType(SubscribeConfig.SUBSCRIBE_TYPE_ACTIVE)',
+        'android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build()',
+        'android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setPmk(byte[])',
+        ]
+    )
+
     def test_ib_solicited_active_pmk_specific(self):
         """Data-path: in-band, solicited/active, PMK, specific peer
 
@@ -1778,6 +1873,15 @@
             encr_type=self.ENCR_TYPE_PMK,
             use_peer_id=True)
 
+    @ApiTest(
+    apis=[
+        'android.net.wifi.aware.PublishConfig.Builder#setPublishType(PublishConfig.PUBLISH_TYPE_SOLICITED)',
+        'android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType(SubscribeConfig.SUBSCRIBE_TYPE_ACTIVE)',
+        'android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build()',
+        'android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setPmk(byte[])',
+        ]
+    )
+
     def test_ib_solicited_active_pmk_any(self):
         """Data-path: in-band, solicited/active, PMK, any peer
 
@@ -1809,9 +1913,17 @@
     # peer using the Aware-provided peer handle (as opposed to a MAC address).
     #######################################
 
+    @ApiTest(
+    apis=[
+        'android.net.wifi.aware.PublishConfig.Builder#setPublishType(PublishConfig.PUBLISH_TYPE_UNSOLICITED)',
+        'android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType(SubscribeConfig.SUBSCRIBE_TYPE_PASSIVE)',
+        'android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build()',
+        ]
+    )
+
     def test_ib_extra_pub_same_unsolicited_passive_open_specific(self):
         """Data-path: in-band, unsolicited/passive, open encryption.
-                      specific peer.
+                    specific peer.
 
         Configuration contains a publisher (for the same service)
         running on *both* devices.
@@ -1826,10 +1938,17 @@
             pub_on_both=True,
             pub_on_both_same=True)
 
+    @ApiTest(
+    apis=[
+        'android.net.wifi.aware.PublishConfig.Builder#setPublishType(PublishConfig.PUBLISH_TYPE_UNSOLICITED)',
+        'android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType(SubscribeConfig.SUBSCRIBE_TYPE_PASSIVE)',
+        'android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build()',
+        ]
+    )
 
     def test_ib_extra_pub_same_unsolicited_passive_open_any(self):
         """Data-path: in-band, unsolicited/passive, open encryption.
-                      any peer.
+                    any peer.
 
         Configuration contains a publisher (for the same service) running on
         *both* devices.
@@ -1844,9 +1963,17 @@
             pub_on_both=True,
             pub_on_both_same=True)
 
+    @ApiTest(
+    apis=[
+        'android.net.wifi.aware.PublishConfig.Builder#setPublishType(PublishConfig.PUBLISH_TYPE_UNSOLICITED)',
+        'android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType(SubscribeConfig.SUBSCRIBE_TYPE_PASSIVE)',
+        'android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build()',
+        ]
+    )
+
     def test_ib_extra_pub_diff_unsolicited_passive_open_specific(self):
         """Data-path: in-band, unsolicited/passive, open encryption.
-                      specific peer.
+                    specific peer.
 
         Configuration contains a publisher (for a different service) running on
         *both* devices.
@@ -1861,6 +1988,14 @@
             pub_on_both=True,
             pub_on_both_same=False)
 
+    @ApiTest(
+    apis=[
+        'android.net.wifi.aware.PublishConfig.Builder#setPublishType(PublishConfig.PUBLISH_TYPE_UNSOLICITED)',
+        'android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType(SubscribeConfig.SUBSCRIBE_TYPE_PASSIVE)',
+        'android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build()',
+        ]
+    )
+
     def test_ib_extra_pub_diff_unsolicited_passive_open_any(self):
         """Data-path: in-band, unsolicited/passive, open encryption, any peer.
 
@@ -1879,6 +2014,14 @@
 
     ##############################################################
 
+    @ApiTest(
+    apis=[
+        'android.net.wifi.aware.WifiAwareSession#subscrible(android.net.wifi.aware.SubscribeConfig, android.net.wifi.aware.DiscoverySessionCallback, android.os.Handler)',
+        'android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build()',
+        'android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setPskPassphrase(String)',
+        ]
+    )
+
     def test_passphrase_min(self):
         """Data-path: minimum passphrase length
 
@@ -1891,11 +2034,19 @@
             use_peer_id=False,
             passphrase_to_use=self.PASSPHRASE_MIN)
 
+    @ApiTest(
+    apis=[
+        'android.net.wifi.aware.WifiAwareSession#subscrible(android.net.wifi.aware.SubscribeConfig, android.net.wifi.aware.DiscoverySessionCallback, android.os.Handler)',
+        'android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build()',
+        'android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#setPskPassphrase(String)',
+        ]
+    )
+
     def test_passphrase_max(self):
         """Data-path: maximum passphrase length
 
         Use in-band, unsolicited/passive, any peer combination
-         """
+        """
         self.run_ib_data_path_test(
             ptype=_PUBLISH_TYPE_UNSOLICITED,
             stype=_SUBSCRIBE_TYPE_PASSIVE,
@@ -1903,22 +2054,51 @@
             use_peer_id=False,
             passphrase_to_use=self.PASSPHRASE_MAX)
 
+    @ApiTest(
+    apis=[
+        'android.net.wifi.aware.WifiAwareManager#attach(android.net.wifi.aware.AttachCallback, android.net.wifi.aware.IdentityChangedListener, android.os.Handler)',
+        'android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierOpen(byte[])',
+        ]
+    )
+
     def test_negative_mismatch_init_mac(self):
         """Data-path: failure when Initiator MAC address mismatch"""
         self.run_mismatched_oob_data_path_test(
             init_mismatch_mac=True, resp_mismatch_mac=False)
 
+    @ApiTest(
+    apis=[
+        'android.net.wifi.aware.WifiAwareManager#attach(android.net.wifi.aware.AttachCallback, android.net.wifi.aware.IdentityChangedListener, android.os.Handler)',
+        'android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierOpen(byte[])',
+        ]
+    )
+
     def test_negative_mismatch_resp_mac(self):
         """Data-path: failure when Responder MAC address mismatch"""
         self.run_mismatched_oob_data_path_test(
             init_mismatch_mac=False, resp_mismatch_mac=True)
 
+    @ApiTest(
+    apis=[
+        'android.net.wifi.aware.WifiAwareManager#attach(android.net.wifi.aware.AttachCallback, android.net.wifi.aware.IdentityChangedListener, android.os.Handler)',
+        'android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierPassphrase(byte[],string)',
+        ]
+    )
+
     def test_negative_mismatch_passphrase(self):
         """Data-path: failure when passphrases mismatch"""
         self.run_mismatched_oob_data_path_test(
             init_encr_type=self.ENCR_TYPE_PASSPHRASE,
             resp_encr_type=self.ENCR_TYPE_PASSPHRASE)
 
+    @ApiTest(
+    apis=[
+        'android.net.wifi.aware.WifiAwareManager#attach(android.net.wifi.aware.AttachCallback, android.net.wifi.aware.IdentityChangedListener, android.os.Handler)',
+        'android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierOpen(byte[])',
+        'android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierPassphrase(byte[],string)',
+        ]
+    )
+
     def test_negative_mismatch_open_passphrase(self):
         """Data-path:
             failure when initiator is open, and responder passphrase
@@ -1927,6 +2107,14 @@
             init_encr_type=self.ENCR_TYPE_OPEN,
             resp_encr_type=self.ENCR_TYPE_PASSPHRASE)
 
+    @ApiTest(
+    apis=[
+        'android.net.wifi.aware.WifiAwareManager#attach(android.net.wifi.aware.AttachCallback, android.net.wifi.aware.IdentityChangedListener, android.os.Handler)',
+        'android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierOpen(byte[])',
+        'android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierPassphrase(byte[],string)',
+        ]
+    )
+
     def test_negative_mismatch_passphrase_open(self):
         """Data-path:
             failure when initiator is passphrase, and responder open
@@ -1935,30 +2123,69 @@
             init_encr_type=self.ENCR_TYPE_PASSPHRASE,
             resp_encr_type=self.ENCR_TYPE_OPEN)
 
+    @ApiTest(
+    apis=[
+        'android.net.wifi.aware.WifiAwareManager#attach(android.net.wifi.aware.AttachCallback, android.net.wifi.aware.IdentityChangedListener, android.os.Handler)',
+        'android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierPmk(byte[],string)',
+        ]
+    )
+
     def test_negative_mismatch_pmk(self):
         """Data-path: failure when PMK mismatch"""
         self.run_mismatched_oob_data_path_test(
             init_encr_type=self.ENCR_TYPE_PMK,
             resp_encr_type=self.ENCR_TYPE_PMK)
 
+    @ApiTest(
+    apis=[
+        'android.net.wifi.aware.WifiAwareManager#attach(android.net.wifi.aware.AttachCallback, android.net.wifi.aware.IdentityChangedListener, android.os.Handler)',
+        'android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierOpen(byte[])',
+        'android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierPmk(byte[],string)',
+        ]
+    )
+
     def test_negative_mismatch_open_pmk(self):
         """Data-path: failure when initiator is open, and responder PMK"""
         self.run_mismatched_oob_data_path_test(
             init_encr_type=self.ENCR_TYPE_OPEN,
             resp_encr_type=self.ENCR_TYPE_PMK)
 
+    @ApiTest(
+    apis=[
+        'android.net.wifi.aware.WifiAwareManager#attach(android.net.wifi.aware.AttachCallback, android.net.wifi.aware.IdentityChangedListener, android.os.Handler)',
+        'android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierPmk(byte[],string)',
+        'android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierPassphrase(byte[],string)',
+        ]
+    )
+
     def test_negative_mismatch_pmk_passphrase(self):
         """Data-path: failure when initiator is pmk, and responder passphrase"""
         self.run_mismatched_oob_data_path_test(
             init_encr_type=self.ENCR_TYPE_PMK,
             resp_encr_type=self.ENCR_TYPE_PASSPHRASE)
 
+    @ApiTest(
+    apis=[
+        'android.net.wifi.aware.WifiAwareManager#attach(android.net.wifi.aware.AttachCallback, android.net.wifi.aware.IdentityChangedListener, android.os.Handler)',
+        'android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierOpen(byte[])',
+        'android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierPmk(byte[],string)',
+        ]
+    )
+
     def test_negative_mismatch_pmk_open(self):
         """Data-path: failure when initiator is PMK, and responder open"""
         self.run_mismatched_oob_data_path_test(
             init_encr_type=self.ENCR_TYPE_PMK,
             resp_encr_type=self.ENCR_TYPE_OPEN)
 
+    @ApiTest(
+    apis=[
+        'android.net.wifi.aware.WifiAwareManager#attach(android.net.wifi.aware.AttachCallback, android.net.wifi.aware.IdentityChangedListener, android.os.Handler)',
+        'android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierPassphrase(byte[],string)',
+        'android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierPmk(byte[],string)',
+        ]
+    )
+
     def test_negative_mismatch_passphrase_pmk(self):
         """Data-path: failure when initiator is passphrase, and responder pmk"""
         self.run_mismatched_oob_data_path_test(
@@ -1981,6 +2208,13 @@
     # and exchange of MAC addresses and then Wi-Fi Aware for data-path.
     #######################################
 
+    @ApiTest(
+    apis=[
+        'android.net.wifi.aware.WifiAwareManager#attach(android.net.wifi.aware.AttachCallback, android.net.wifi.aware.IdentityChangedListener, android.os.Handler)',
+        'android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierOpen(byte[])',
+        ]
+    )
+
     def test_oob_open_specific(self):
         """Data-path: out-of-band, open encryption, specific peer
 
@@ -1989,6 +2223,13 @@
         self.run_oob_data_path_test(
             encr_type=self.ENCR_TYPE_OPEN, use_peer_id=True)
 
+    @ApiTest(
+    apis=[
+        'android.net.wifi.aware.WifiAwareManager#attach(android.net.wifi.aware.AttachCallback, android.net.wifi.aware.IdentityChangedListener, android.os.Handler)',
+        'android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierPassphrase(byte[],string)',
+        ]
+    )
+
     def test_oob_passphrase_specific(self):
         """Data-path: out-of-band, passphrase, specific peer
 
@@ -1997,6 +2238,13 @@
         self.run_oob_data_path_test(
             encr_type=self.ENCR_TYPE_PASSPHRASE, use_peer_id=True)
 
+    @ApiTest(
+    apis=[
+        'android.net.wifi.aware.WifiAwareManager#attach(android.net.wifi.aware.AttachCallback, android.net.wifi.aware.IdentityChangedListener, android.os.Handler)',
+        'android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierPmk(byte[],string)',
+        ]
+    )
+
     def test_oob_pmk_specific(self):
         """Data-path: out-of-band, PMK, specific peer
 
@@ -2005,6 +2253,15 @@
         self.run_oob_data_path_test(
             encr_type=self.ENCR_TYPE_PMK, use_peer_id=True)
 
+    @ApiTest(
+    apis=[
+        'android.net.wifi.aware.WifiAwareManager#attach(android.net.wifi.aware.AttachCallback, android.net.wifi.aware.IdentityChangedListener, android.os.Handler)',
+        'android.net.wifi.aware.PublishConfig.Builder#setPublishType(PublishConfig.PUBLISH_TYPE_UNSOLICITED)',
+        'android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType(SubscribeConfig.SUBSCRIBE_TYPE_PASSIVE)',
+        'android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierOpen(byte[])',
+        ]
+    )
+
     def test_oob_ib_coex_open_specific(self):
         """Data-path: out-of-band, open encryption, specific peer - in-band coex:
     set up a concurrent discovery session to verify no impact. The session
@@ -2016,6 +2273,15 @@
             encr_type=self.ENCR_TYPE_OPEN,
             setup_discovery_sessions=True , use_peer_id=True)
 
+    @ApiTest(
+    apis=[
+        'android.net.wifi.aware.WifiAwareManager#attach(android.net.wifi.aware.AttachCallback, android.net.wifi.aware.IdentityChangedListener, android.os.Handler)',
+        'android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierPmk(byte[],string)',
+        'android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierPassphrase(byte[],string)',
+        'android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE',
+        ]
+    )
+
     def test_multiple_identical_networks(self):
         """Validate that creating multiple networks between 2 devices, each network
         with identical configuration is supported over a single NDP.
@@ -2150,6 +2416,15 @@
             init_dut.wifi_aware_snippet.connectivityUnregisterNetwork(
                 init_req_callback_event.callback_id)
 
+    @ApiTest(
+    apis=[
+        'android.net.wifi.aware.WifiAwareManager#attach(android.net.wifi.aware.AttachCallback, android.net.wifi.aware.IdentityChangedListener, android.os.Handler)',
+        'android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierPmk(byte[],string)',
+        'android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierPassphrase(byte[],string)',
+        'android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE',
+        ]
+    )
+
     def test_identical_network_from_both_sides(self):
         """Validate that requesting two identical NDPs (Open) each being initiated
         from a different side, results in the same/single NDP.
@@ -2550,6 +2825,15 @@
             dut2.wifi_aware_snippet.connectivityUnregisterNetwork(
                 dut2_key_even.callback_id)
 
+    @ApiTest(
+    apis=[
+        'android.net.wifi.aware.WifiAwareManager#attach(android.net.wifi.aware.AttachCallback, android.net.wifi.aware.IdentityChangedListener, android.os.Handler)',
+        'android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierOpen(byte[])',
+        'android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierPassphrase(byte[],string)',
+        'android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE',
+        ]
+    )
+
     def test_multiple_ndi_open_passphrase(self):
         """Verify that between 2 DUTs can create 2 NDPs with different security
         configuration (one open, one using passphrase). The result should use
@@ -2558,6 +2842,14 @@
         # self.run_multiple_ndi(self.PASSPHRASE)
         self.run_multiple_ndi([None, self.PASSPHRASE])
 
+    @ApiTest(
+    apis=[
+        'android.net.wifi.aware.WifiAwareManager#attach(android.net.wifi.aware.AttachCallback, android.net.wifi.aware.IdentityChangedListener, android.os.Handler)',
+        'android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierPassphrase(byte[],string)',
+        'android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE',
+        ]
+    )
+
     def test_multiple_ndi_passphrases(self):
         """Verify that between 2 DUTs can create 2 NDPs with different security
         configuration (using different passphrases). The result should use two
@@ -2565,6 +2857,15 @@
         """
         self.run_multiple_ndi([self.PASSPHRASE, self.PASSPHRASE2])
 
+    @ApiTest(
+    apis=[
+        'android.net.wifi.aware.WifiAwareManager#attach(android.net.wifi.aware.AttachCallback, android.net.wifi.aware.IdentityChangedListener, android.os.Handler)',
+        'android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierOpen(byte[])',
+        'android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierPassphrase(byte[],string)',
+        'android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE',
+        ]
+    )
+
     def test_multiple_ndi_open_passphrase_flip(self):
         """Verify that between 2 DUTs can create 2 NDPs with different security
         configuration (one open, one using passphrase). The result should use
@@ -2574,6 +2875,14 @@
         """
         self.run_multiple_ndi([None, self.PASSPHRASE], flip_init_resp=True)
 
+    @ApiTest(
+    apis=[
+        'android.net.wifi.aware.WifiAwareManager#attach(android.net.wifi.aware.AttachCallback, android.net.wifi.aware.IdentityChangedListener, android.os.Handler)',
+        'android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierPassphrase(byte[],string)',
+        'android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE',
+        ]
+    )
+
     def test_multiple_ndi_passphrases_flip(self):
         """Verify that between 2 DUTs can create 2 NDPs with different security
         configuration (using different passphrases). The result should use two
@@ -2584,6 +2893,15 @@
         self.run_multiple_ndi(
             [self.PASSPHRASE, self.PASSPHRASE2], flip_init_resp=True)
 
+    @ApiTest(
+    apis=[
+        'android.net.wifi.aware.WifiAwareManager#attach(android.net.wifi.aware.AttachCallback, android.net.wifi.aware.IdentityChangedListener, android.os.Handler)',
+        'android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierOpen(byte[])',
+        'android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierPmk(byte[],string)',
+        'android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE',
+        ]
+    )
+
     def test_multiple_ndi_open_pmk(self):
         """Verify that between 2 DUTs can create 2 NDPs with different security
         configuration (one open, one using pmk). The result should use two
@@ -2591,6 +2909,15 @@
         """
         self.run_multiple_ndi([None, self.PMK])
 
+    @ApiTest(
+    apis=[
+        'android.net.wifi.aware.WifiAwareManager#attach(android.net.wifi.aware.AttachCallback, android.net.wifi.aware.IdentityChangedListener, android.os.Handler)',
+        'android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierPassphrase(byte[],string)',
+        'android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierPmk(byte[],string)',
+        'android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE',
+        ]
+    )
+
     def test_multiple_ndi_passphrase_pmk(self):
         """Verify that between 2 DUTs can create 2 NDPs with different security
         configuration (one using passphrase, one using pmk). The result should
@@ -2598,6 +2925,14 @@
         """
         self.run_multiple_ndi([self.PASSPHRASE, self.PMK])
 
+    @ApiTest(
+    apis=[
+        'android.net.wifi.aware.WifiAwareManager#attach(android.net.wifi.aware.AttachCallback, android.net.wifi.aware.IdentityChangedListener, android.os.Handler)',
+        'android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierPmk(byte[],string)',
+        'android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE',
+        ]
+    )
+
     def test_multiple_ndi_pmks(self):
         """Verify that between 2 DUTs can create 2 NDPs with different security
         configuration (using different PMKS). The result should use two
@@ -2605,6 +2940,15 @@
         """
         self.run_multiple_ndi([self.PMK, self.PMK2])
 
+    @ApiTest(
+    apis=[
+        'android.net.wifi.aware.WifiAwareManager#attach(android.net.wifi.aware.AttachCallback, android.net.wifi.aware.IdentityChangedListener, android.os.Handler)',
+        'android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierOpen(byte[])',
+        'android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierPmk(byte[],string)',
+        'android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE',
+        ]
+    )
+
     def test_multiple_ndi_open_pmk_flip(self):
         """Verify that between 2 DUTs can create 2 NDPs with different security
         configuration (one open, one using pmk). The result should use two
@@ -2614,6 +2958,15 @@
         """
         self.run_multiple_ndi([None, self.PMK], flip_init_resp=True)
 
+    @ApiTest(
+    apis=[
+        'android.net.wifi.aware.WifiAwareManager#attach(android.net.wifi.aware.AttachCallback, android.net.wifi.aware.IdentityChangedListener, android.os.Handler)',
+        'android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierPassphrase(byte[],string)',
+        'android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierPmk(byte[],string)',
+        'android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE',
+        ]
+    )
+
     def test_multiple_ndi_passphrase_pmk_flip(self):
         """Verify that between 2 DUTs can create 2 NDPs with different security
         configuration (one using passphrase, one using pmk). The result should
@@ -2623,6 +2976,14 @@
         """
         self.run_multiple_ndi([self.PASSPHRASE, self.PMK], flip_init_resp=True)
 
+    @ApiTest(
+    apis=[
+        'android.net.wifi.aware.WifiAwareManager#attach(android.net.wifi.aware.AttachCallback, android.net.wifi.aware.IdentityChangedListener, android.os.Handler)',
+        'android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierPmk(byte[],string)',
+        'android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE',
+        ]
+    )
+
     def test_multiple_ndi_pmks_flip(self):
         """Verify that between 2 DUTs can create 2 NDPs with different security
         configuration (using different PMKS). The result should use two
@@ -2649,6 +3010,16 @@
     #
     #######################################
 
+    @ApiTest(
+    apis=[
+        'android.net.wifi.aware.WifiAwareManager#attach(android.net.wifi.aware.AttachCallback, android.net.wifi.aware.IdentityChangedListener, android.os.Handler)',
+        'android.net.wifi.aware.PublishConfig.Builder#setPublishType(PublishConfig.PUBLISH_TYPE_UNSOLICITED)',
+        'android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType(SubscribeConfig.SUBSCRIBE_TYPE_PASSIVE)',
+        'android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build()',
+        'android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierOpen(byte[])',
+        ]
+    )
+
     def test_identical_ndps_mix_ib_oob_ib_first_same_polarity(self):
         """Validate that a single NDP is created for multiple identical
         requests which are issued through either in-band (ib) or out-of-band
@@ -2660,6 +3031,16 @@
         self.run_mix_ib_oob(
             same_request=True, ib_first=True, inits_on_same_dut=True)
 
+    @ApiTest(
+    apis=[
+        'android.net.wifi.aware.WifiAwareManager#attach(android.net.wifi.aware.AttachCallback, android.net.wifi.aware.IdentityChangedListener, android.os.Handler)',
+        'android.net.wifi.aware.PublishConfig.Builder#setPublishType(PublishConfig.PUBLISH_TYPE_UNSOLICITED)',
+        'android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType(SubscribeConfig.SUBSCRIBE_TYPE_PASSIVE)',
+        'android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build()',
+        'android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierOpen(byte[])',
+        ]
+    )
+
     def test_identical_ndps_mix_ib_oob_oob_first_same_polarity(self):
         """Validate that a single NDP is created for multiple identical
         requests which are issued through either in-band (ib) or out-of-band
@@ -2672,6 +3053,16 @@
         self.run_mix_ib_oob(
             same_request=True, ib_first=False, inits_on_same_dut=True)
 
+    @ApiTest(
+    apis=[
+        'android.net.wifi.aware.WifiAwareManager#attach(android.net.wifi.aware.AttachCallback, android.net.wifi.aware.IdentityChangedListener, android.os.Handler)',
+        'android.net.wifi.aware.PublishConfig.Builder#setPublishType(PublishConfig.PUBLISH_TYPE_UNSOLICITED)',
+        'android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType(SubscribeConfig.SUBSCRIBE_TYPE_PASSIVE)',
+        'android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build()',
+        'android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierOpen(byte[])',
+        ]
+    )
+
     def test_identical_ndps_mix_ib_oob_ib_first_diff_polarity(self):
         """Validate that a single NDP is created for multiple identical
         requests which are issued through either in-band (ib) or out-of-band
@@ -2683,6 +3074,16 @@
         self.run_mix_ib_oob(
             same_request=True, ib_first=True, inits_on_same_dut=False)
 
+    @ApiTest(
+    apis=[
+        'android.net.wifi.aware.WifiAwareManager#attach(android.net.wifi.aware.AttachCallback, android.net.wifi.aware.IdentityChangedListener, android.os.Handler)',
+        'android.net.wifi.aware.PublishConfig.Builder#setPublishType(PublishConfig.PUBLISH_TYPE_UNSOLICITED)',
+        'android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType(SubscribeConfig.SUBSCRIBE_TYPE_PASSIVE)',
+        'android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build()',
+        'android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierOpen(byte[])',
+        ]
+    )
+
     def test_identical_ndps_mix_ib_oob_oob_first_diff_polarity(self):
         """Validate that a single NDP is created for multiple identical
         requests which are issued through either in-band (ib) or out-of-band
@@ -2694,6 +3095,16 @@
         self.run_mix_ib_oob(
             same_request=True, ib_first=False, inits_on_same_dut=False)
 
+    @ApiTest(
+    apis=[
+        'android.net.wifi.aware.WifiAwareManager#attach(android.net.wifi.aware.AttachCallback, android.net.wifi.aware.IdentityChangedListener, android.os.Handler)',
+        'android.net.wifi.aware.PublishConfig.Builder#setPublishType(PublishConfig.PUBLISH_TYPE_UNSOLICITED)',
+        'android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType(SubscribeConfig.SUBSCRIBE_TYPE_PASSIVE)',
+        'android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build()',
+        'android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierPassphrase(byte[],string)',
+        ]
+    )
+
     def test_multiple_ndis_mix_ib_oob_ib_first_same_polarity(self):
 
         """Validate that multiple NDIs are created for NDPs which are requested
@@ -2706,6 +3117,16 @@
         self.run_mix_ib_oob(
             same_request=False, ib_first=True, inits_on_same_dut=True)
 
+    @ApiTest(
+    apis=[
+        'android.net.wifi.aware.WifiAwareManager#attach(android.net.wifi.aware.AttachCallback, android.net.wifi.aware.IdentityChangedListener, android.os.Handler)',
+        'android.net.wifi.aware.PublishConfig.Builder#setPublishType(PublishConfig.PUBLISH_TYPE_UNSOLICITED)',
+        'android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType(SubscribeConfig.SUBSCRIBE_TYPE_PASSIVE)',
+        'android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build()',
+        'android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierPassphrase(byte[],string)',
+        ]
+    )
+
     def test_multiple_ndis_mix_ib_oob_oob_first_same_polarity(self):
         """Validate that multiple NDIs are created for NDPs which are requested
         with different security configurations. Use a mix of in-band and
@@ -2717,6 +3138,16 @@
         self.run_mix_ib_oob(
             same_request=False, ib_first=False, inits_on_same_dut=True)
 
+    @ApiTest(
+    apis=[
+        'android.net.wifi.aware.WifiAwareManager#attach(android.net.wifi.aware.AttachCallback, android.net.wifi.aware.IdentityChangedListener, android.os.Handler)',
+        'android.net.wifi.aware.PublishConfig.Builder#setPublishType(PublishConfig.PUBLISH_TYPE_UNSOLICITED)',
+        'android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType(SubscribeConfig.SUBSCRIBE_TYPE_PASSIVE)',
+        'android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build()',
+        'android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierPassphrase(byte[],string)',
+        ]
+    )
+
     def test_multiple_ndis_mix_ib_oob_ib_first_diff_polarity(self):
         """Validate that multiple NDIs are created for NDPs which are requested
         with different security configurations. Use a mix of in-band and
@@ -2728,6 +3159,15 @@
         self.run_mix_ib_oob(
             same_request=False, ib_first=True, inits_on_same_dut=False)
 
+    @ApiTest(
+    apis=[
+        'android.net.wifi.aware.WifiAwareManager#attach(android.net.wifi.aware.AttachCallback, android.net.wifi.aware.IdentityChangedListener, android.os.Handler)',
+        'android.net.wifi.aware.PublishConfig.Builder#setPublishType(PublishConfig.PUBLISH_TYPE_UNSOLICITED)',
+        'android.net.wifi.aware.SubscribeConfig.Builder#setSubscribeType(SubscribeConfig.SUBSCRIBE_TYPE_PASSIVE)',
+        'android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build()',
+        'android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierPassphrase(byte[],string)',
+        ]
+    )
 
     def test_multiple_ndis_mix_ib_oob_oob_first_diff_polarity(self):
         """Validate that multiple NDIs are created for NDPs which are requested
@@ -2749,6 +3189,16 @@
     #
     #######################################
 
+    @ApiTest(
+    apis=[
+        'android.net.wifi.aware.WifiAwareManager#attach(android.net.wifi.aware.AttachCallback, android.net.wifi.aware.IdentityChangedListener, android.os.Handler)',
+        'android.net.wifi.aware.WifiAwareSession#publish(android.net.wifi.aware.PublishConfig, android.net.wifi.aware.DiscoverySessionCallback, android.os.Handler)',
+        'android.net.wifi.aware.WifiAwareSession#subscrible(android.net.wifi.aware.SubscribeConfig, android.net.wifi.aware.DiscoverySessionCallback, android.os.Handler)',
+        'android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder#build',
+        'android.net.wifi.aware.WifiAwareSession#createNetworkSpecifierOpen(byte[])',
+        ]
+    )
+
     def test_multiple_regulator_domains_ib_us_jp(self):
         """Verify data-path setup across multiple regulator domains.
 
diff --git a/tests/hostsidetests/multidevices/test/aware/integration/wifi_rtt_disable_test.py b/tests/hostsidetests/multidevices/test/aware/integration/wifi_rtt_disable_test.py
new file mode 100644
index 0000000..d87de30
--- /dev/null
+++ b/tests/hostsidetests/multidevices/test/aware/integration/wifi_rtt_disable_test.py
@@ -0,0 +1,375 @@
+#  Copyright (C) 2024 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.
+
+# Lint as: python3
+"""Wi-Fi Aware Rtt Disable test reimplemented in Mobly."""
+import functools
+import logging
+import signal
+import sys
+import time
+
+from aware import aware_lib_utils as autils
+from aware import constants
+from mobly import asserts
+from mobly import base_test
+from mobly import records
+from mobly import test_runner
+from mobly import utils
+from mobly.controllers import android_device
+from mobly.snippet import errors
+
+RUNTIME_PERMISSIONS = (
+    'android.permission.ACCESS_FINE_LOCATION',
+    'android.permission.ACCESS_COARSE_LOCATION',
+    'android.permission.NEARBY_WIFI_DEVICES',
+)
+PACKAGE_NAME = constants.WIFI_AWARE_SNIPPET_PACKAGE_NAME
+
+# Alias variable.
+_DEFAULT_TIMEOUT = constants.WAIT_WIFI_STATE_TIME_OUT.total_seconds()
+_CALLBACK_NAME = constants.DiscoverySessionCallbackParamsType.CALLBACK_NAME
+
+######################################################
+# status codes
+######################################################
+_RANGING_FAIL_CODE_GENERIC = 1
+_RANGING_FAIL_CODE_RTT_NOT_AVAILABLE = 2
+
+
+# Timeout decorator block
+class TimeoutError(Exception):
+  """Exception for timeout decorator related errors."""
+
+
+def _timeout_handler():
+  """Handler function used by signal to terminate a timed out function."""
+  raise TimeoutError()
+
+
+def timeout(sec):
+  """A decorator used to add time out check to a function.
+
+  This only works in main thread due to its dependency on signal module.
+  Do NOT use it if the decorated function does not run in the Main thread.
+
+  Args:
+      sec: Number of seconds to wait before the function times out. No timeout
+        if set to 0
+
+  Returns:
+      What the decorated function returns.
+
+  Raises:
+      TimeoutError is raised when time out happens.
+  """
+
+  def decorator(func):
+
+    @functools.wraps(func)
+    def wrapper(*args, **kwargs):
+      if sec:
+        signal.signal(signal.SIGALRM, _timeout_handler)
+        signal.alarm(sec)
+      try:
+        return func(*args, **kwargs)
+      except TimeoutError as exc:
+        raise TimeoutError(
+            ('Function {} timed out after {} seconds.').format(
+                func.__name__, sec
+            )
+        ) from exc
+      finally:
+        signal.alarm(0)
+
+    return wrapper
+
+  return decorator
+
+
+class RttDisableTest(base_test.BaseTestClass):
+  """Test class for RTT ranging enable/disable flows."""
+
+  MODE_DISABLE_WIFI = 0
+  MODE_DISABLE_LOCATIONING = 1
+
+  ads: list[android_device.AndroidDevice]
+
+  def setup_class(self):
+    self.ads = self.register_controller(android_device, min_number=1)
+
+    def setup_device(device: android_device.AndroidDevice):
+      autils.control_wifi(device, True)
+      device.load_snippet('wifi_aware_snippet', PACKAGE_NAME)
+      for permission in RUNTIME_PERMISSIONS:
+        device.adb.shell(['pm', 'grant', PACKAGE_NAME, permission])
+      asserts.abort_all_if(
+          not device.wifi_aware_snippet.wifiAwareIsAvailable(),
+          f'{device} Wi-Fi Aware is not available.',
+      )
+
+    # Set up devices in parallel.
+    utils.concurrent_exec(
+        setup_device,
+        param_list=[[ad] for ad in self.ads],
+        max_workers=1,
+        raise_on_exception=True,
+    )
+
+  def setup_test(self):
+    for ad in self.ads:
+      autils.control_wifi(ad, True)
+      self.set_location_service(ad, True)
+      aware_avail = ad.wifi_aware_snippet.wifiAwareIsAvailable()
+      if not aware_avail:
+        ad.log.info('Aware not available. Waiting ...')
+        state_handler = ad.wifi_aware_snippet.wifiAwareMonitorStateChange()
+        state_handler.waitAndGet(
+            constants.WifiAwareBroadcast.WIFI_AWARE_AVAILABLE
+        )
+
+  def teardown_test(self):
+    utils.concurrent_exec(
+        self._teardown_test_on_device,
+        param_list=[[ad] for ad in self.ads],
+        max_workers=1,
+        raise_on_exception=True,
+    )
+    utils.concurrent_exec(
+        lambda d: d.services.create_output_excerpts_all(self.current_test_info),
+        param_list=[[ad] for ad in self.ads],
+        raise_on_exception=True,
+    )
+
+  def _teardown_test_on_device(self, ad: android_device.AndroidDevice) -> None:
+    ad.wifi_aware_snippet.wifiAwareCloseAllWifiAwareSession()
+    ad.wifi_aware_snippet.wifiAwareMonitorStopStateChange()
+    # autils.control_wifi(ad, True)
+
+  def on_fail(self, record: records.TestResult) -> None:
+    android_device.take_bug_reports(
+        self.ads, destination=self.current_test_info.output_path
+    )
+
+  def scan_networks(
+      self, dut: android_device.AndroidDevice, max_tries: int = 3
+  ) -> list[dict[str, str]]:
+    """Perform a scan and return scan results.
+
+    Args:
+        dut: Device under test.
+        max_tries: Retry scan to ensure network is found
+
+    Returns:
+        an array of scan results.
+    """
+    scan_results = []
+    for _ in range(max_tries):
+        scan_results = dut.wifi_aware_snippet.wifiScanAndGetResults()
+        if scan_results:
+            break
+
+    return scan_results
+
+  def select_best_scan_results(
+      self,
+      scans: list[dict[str, str]],
+      select_count: int,
+      lowest_rssi: int = -80,
+  ):
+    """Select best result based on RSSI.
+
+    Select the strongest 'select_count' scans in the input list based on
+    highest RSSI. Exclude all very weak signals, even if results in a shorter
+    list.
+
+    Args:
+        scans: List of scan results.
+        select_count: An integer specifying how many scans to return at most.
+        lowest_rssi: The lowest RSSI to accept into the output.
+
+    Returns:
+           a list of the strongest 'select_count' scan results from the scans
+           list.
+    """
+
+    def _take_rssi(element):
+      return element['level']
+
+    result = []
+    scans.sort(key=_take_rssi, reverse=True)
+    for scan in scans:
+      logging.info(
+          'scan type: %s, %s, %s', scan['SSID'], scan['level'], scan['BSSID']
+      )
+      if len(result) == select_count:
+        break
+      if scan['level'] < lowest_rssi:
+        break  # rest are lower since we're sorted
+      result.append(scan)
+
+    return result
+
+  def set_location_service(self, ad, new_state):
+    """Set Location service on/off in Settings->Location.
+
+    Args:
+        ad: android device object.
+        new_state: new state for "Location service".
+            If new_state is False, turn off location service.
+            If new_state if True, set location service to "High accuracy".
+    """
+    ad.adb.shell('content insert --uri '
+                 ' content://com.google.settings/partner --bind '
+                 'name:s:network_location_opt_in --bind value:s:1')
+    ad.adb.shell('content insert --uri '
+                 ' content://com.google.settings/partner --bind '
+                 'name:s:use_location_for_services --bind value:s:1')
+    if new_state:
+        ad.adb.shell('settings put secure location_mode 3')
+    else:
+        ad.adb.shell('settings put secure location_mode 0')
+
+  def force_airplane_mode(self, ad, new_state, timeout_value=60):
+    """Force the device to set airplane mode on or off by adb shell command.
+
+    Args:
+        ad: android device object.
+        new_state: Turn on airplane mode if True.
+            Turn off airplane mode if False.
+        timeout_value: max wait time for 'adb wait-for-device'
+
+    Returns:
+        True if success.
+        False if timeout.
+    """
+
+    # Using timeout decorator.
+    # Wait for device with timeout. If after <timeout_value> seconds, adb
+    # is still waiting for device, throw TimeoutError exception.
+    @timeout(timeout_value)
+    def wait_for_device_with_timeout(ad):
+        ad.adb.wait_for_device()
+
+    try:
+        wait_for_device_with_timeout(ad)
+        ad.adb.shell('settings put global airplane_mode_on {}'.format(
+            1 if new_state else 0))
+        ad.adb.shell('am broadcast -a android.intent.action.AIRPLANE_MODE')
+    except TimeoutError:
+        # adb wait for device timeout
+        return False
+    return True
+
+  def run_disable_rtt(self, disable_mode):
+    """Validate the RTT ranging feature if RTT disabled.
+
+    Validate the RTT disabled flows: whether by disabling Wi-Fi or entering
+    doze mode.
+
+    Args:
+      disable_mode: The particular mechanism in which RTT is disabled. One of
+        the MODE_* constants.
+    """
+    dut = self.ads[0]
+
+    # validate start-up conditions
+    asserts.assert_true(
+        dut.wifi_aware_snippet.wifiRttIsAvailable(), 'RTT is not available'
+    )
+
+    # scan to get some APs to be used later
+    all_aps = self.select_best_scan_results(
+        self.scan_networks(dut), select_count=1
+    )
+    asserts.assert_true(all_aps, 'Need at least one visible AP!')
+
+    # disable RTT and validate broadcast & API
+    if disable_mode == self.MODE_DISABLE_WIFI:
+      # disabling Wi-Fi is not sufficient: since scan mode (and hence RTT) will
+      # remain enabled - we need to disable the Wi-Fi chip aka Airplane Mode
+      asserts.assert_true(
+          self.force_airplane_mode(dut, True),
+          'Can not turn on airplane mode on: %s' % dut.serial,
+      )
+      autils.control_wifi(dut, False)
+    elif disable_mode == self.MODE_DISABLE_LOCATIONING:
+      self.set_location_service(dut, False)
+    time.sleep(10)
+    dut.log.info(
+        'WiFi RTT status: %s', dut.wifi_aware_snippet.wifiRttIsAvailable()
+    )
+    asserts.assert_false(
+        dut.wifi_aware_snippet.wifiRttIsAvailable(), 'RTT is available'
+    )
+
+    # request a range and validate error
+    dut.log.info('access points input: %s', all_aps[0:1])
+    ranging_cb_handler = (
+        dut.wifi_aware_snippet.wifiRttStartRangingToAccessPoints(all_aps[0:1])
+    )
+    event = ranging_cb_handler.waitAndGet(
+        event_name=constants.RangingResultCb.EVENT_NAME_ON_RANGING_RESULT,
+        timeout=_DEFAULT_TIMEOUT,
+    )
+
+    callback_name = event.data.get(
+        constants.RangingResultCb.DATA_KEY_CALLBACK_NAME, None
+    )
+    dut.log.info('StartRangingToAccessPoints callback = %s', callback_name)
+    asserts.assert_equal(
+        callback_name,
+        constants.RangingResultCb.CB_METHOD_ON_RANGING_FAILURE,
+        'Should be ranging failed.',
+    )
+    status_code = event.data.get(
+        constants.RangingResultCb.DATA_KEY_RESULT_STATUS, None
+    )
+    dut.log.info('StartRangingToAccessPoints status code = %s', status_code)
+    asserts.assert_equal(
+        status_code, _RANGING_FAIL_CODE_RTT_NOT_AVAILABLE, 'Invalid error code'
+    )
+
+    # enable RTT and validate broadcast & API
+    if disable_mode == self.MODE_DISABLE_WIFI:
+      asserts.assert_true(
+          self.force_airplane_mode(dut, False),
+          'Can not turn off airplane mode on: %s' % dut.serial,
+      )
+      autils.control_wifi(dut, True)
+    elif disable_mode == self.MODE_DISABLE_LOCATIONING:
+      self.set_location_service(dut, True)
+
+    asserts.assert_true(
+        dut.wifi_aware_snippet.wifiRttIsAvailable(), 'RTT is not available'
+    )
+
+  def test_disable_wifi(self):
+    """Validate that getting expected broadcast when Wi-Fi is disabled and that any range requests are rejected.
+    """
+    self.run_disable_rtt(self.MODE_DISABLE_WIFI)
+
+  def test_disable_location(self):
+    """Validate that getting expected broadcast when locationing is disabled and that any range requests are rejected.
+    """
+    self.run_disable_rtt(self.MODE_DISABLE_LOCATIONING)
+
+
+if __name__ == '__main__':
+  # Take test args
+  if '--' in sys.argv:
+    index = sys.argv.index('--')
+    sys.argv = sys.argv[:1] + sys.argv[index + 1 :]
+
+  test_runner.main()
diff --git a/tests/hostsidetests/multidevices/test/direct/constants.py b/tests/hostsidetests/multidevices/test/direct/constants.py
index 903b108..a3bcdf5 100644
--- a/tests/hostsidetests/multidevices/test/direct/constants.py
+++ b/tests/hostsidetests/multidevices/test/direct/constants.py
@@ -52,6 +52,7 @@
 EXTRA_WIFI_P2P_GROUP = 'p2pGroupInfo'
 EXTRA_WIFI_STATE = 'wifi_p2p_state'
 
+ON_CONNECTION_INFO_AVAILABLE = 'WifiP2pOnConnectionInfoAvailable'
 ON_DEVICE_INFO_AVAILABLE = 'WifiP2pOnDeviceInfoAvailable'
 ON_PERSISTENT_GROUP_INFO_AVAILABLE = 'onPersistentGroupInfoAvailable'
 ON_UPNP_SERVICE_AVAILABLE = 'onUpnpServiceAvailable'
diff --git a/tests/hostsidetests/multidevices/test/direct/integration/Android.bp b/tests/hostsidetests/multidevices/test/direct/integration/Android.bp
new file mode 100644
index 0000000..c1332f5
--- /dev/null
+++ b/tests/hostsidetests/multidevices/test/direct/integration/Android.bp
@@ -0,0 +1,50 @@
+// 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 {
+    default_team: "trendy_team_fwk_wifi_hal",
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+python_library_host {
+    name: "wifi_p2p_lib",
+    srcs: ["wifi_p2p_lib.py"],
+}
+
+python_test_host {
+    name: "WifiP2pGroupTestCases",
+    main: "wifi_p2p_group_test.py",
+    srcs: [
+        "wifi_p2p_group_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_group_test.py b/tests/hostsidetests/multidevices/test/direct/integration/wifi_p2p_group_test.py
new file mode 100644
index 0000000..a34255e
--- /dev/null
+++ b/tests/hostsidetests/multidevices/test/direct/integration/wifi_p2p_group_test.py
@@ -0,0 +1,197 @@
+#  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 P2p Group Test reimplemented in Mobly."""
+
+from collections.abc import Sequence
+import datetime
+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 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
+
+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 WifiP2pGroupTest(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_test(self) -> None:
+        for ad in self.ads:
+            ad.wifi.p2pClose()
+
+        utils.concurrent_exec(
+            lambda d: d.services.create_output_excerpts_all(
+                self.current_test_info
+            ),
+            param_list=[[ad] for ad in self.ads],
+            raise_on_exception=True,
+        )
+
+    def p2p_group_join(self, wps_config: constants.WpsInfo):
+        """General flow for p2p group join.
+
+        Steps:
+        1. GO creates a group.
+        2. GC joins the group.
+        3. connection check via ping from GC to GO
+
+        Args:
+            wps_config: WPS configuration for the group.
+        """
+        go_dut = self.ads[0]
+        gc_dut = self.ads[1]
+
+        go_dut.log.info('Initializing Wi-Fi p2p.')
+        group_owner = p2p_utils.setup_wifi_p2p(go_dut)
+        client = p2p_utils.setup_wifi_p2p(gc_dut)
+        # Create a group.
+        p2p_utils.create_group(group_owner, config=None)
+        time.sleep(_DEFAULT_FUNCTION_SWITCH_TIME)
+
+        # Request the connection.
+        wp2putils.p2p_connect(client, group_owner, wps_config,
+                              p2p_connect_type=P2P_CONNECT_JOIN)
+
+        go_ip = wp2putils.p2p_go_ip(gc_dut)
+        wp2putils.p2p_connection_ping_test(gc_dut, go_ip)
+        # Trigger p2p disconnect.
+        p2p_utils.remove_group_and_verify_disconnected(
+            client, group_owner, is_group_negotiation=False
+        )
+        time.sleep(_DEFAULT_FUNCTION_SWITCH_TIME)
+
+    @ApiTest([
+        'android.net.wifi.WpsInfo#PBC',
+        'android.net.wifi.p2p.WifiP2pManager#createGroup(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pConfig, android.net.wifi.p2p.WifiP2pManager.ActionListener)',
+        'android.net.wifi.p2p.WifiP2pManager#connect(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pConfig, android.net.wifi.p2p.WifiP2pManager.ActionListener)',
+        'android.net.wifi.p2p.WifiP2pManager#removeGroup(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener)',
+    ])
+    def test_p2p_group_join_via_pbc(self):
+        """Verify the p2p creates a group and join this group via WPS PBC method."""
+        self.p2p_group_join(constants.WpsInfo.PBC)
+
+    @ApiTest([
+        'android.net.wifi.WpsInfo#DISPLAY',
+        'android.net.wifi.p2p.WifiP2pManager#createGroup(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pConfig, android.net.wifi.p2p.WifiP2pManager.ActionListener)',
+        'android.net.wifi.p2p.WifiP2pManager#connect(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pConfig, android.net.wifi.p2p.WifiP2pManager.ActionListener)',
+        'android.net.wifi.p2p.WifiP2pManager#removeGroup(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener)',
+    ])
+    def test_p2p_group_join_via_display(self):
+        """Verify the p2p creates a group and join this group via WPS DISPLAY method."""
+        self.p2p_group_join(WPS_DISPLAY)
+
+    @ApiTest([
+        'android.net.wifi.p2p.WifiP2pConfig.Builder#setPassphrase(String passphrase)',
+        'android.net.wifi.p2p.WifiP2pConfig.Builder#setGroupOperatingBand(int band)',
+        'android.net.wifi.p2p.WifiP2pManager#createGroup(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pConfig, android.net.wifi.p2p.WifiP2pManager.ActionListener)',
+        'android.net.wifi.p2p.WifiP2pManager#connect(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pConfig, android.net.wifi.p2p.WifiP2pManager.ActionListener)',
+        'android.net.wifi.p2p.WifiP2pManager#removeGroup(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener)',
+    ])
+    def test_p2p_group_with_config(self):
+        """Verify the p2p creates a group and join this group with config.
+
+        Steps:
+        1. GO creates a group with config.
+        2. GC joins the group with config.
+        3. connection check via ping from GC to GO
+        """
+        go_dut = self.ads[0]
+        gc_dut = self.ads[1]
+        # Initialize Wi-Fi p2p on both devices.
+        group_owner = p2p_utils.setup_wifi_p2p(go_dut)
+        client = p2p_utils.setup_wifi_p2p(gc_dut)
+
+        # Create a p2p group on one device (group owner device) with
+        # specific group configuration.
+        p2p_config = constants.WifiP2pConfig(
+            network_name='DIRECT-XY-HELLO-%s' % utils.rand_ascii_str(5),
+            passphrase=self.passphrase,
+            group_operating_band=self.group_band,
+        )
+        p2p_utils.create_group(group_owner, config=p2p_config)
+        time.sleep(_DEFAULT_FUNCTION_SWITCH_TIME)
+        # Request the connection. Since config is known, this is reconnection.
+        p2p_utils.p2p_connect(client, group_owner, p2p_config)
+
+        go_ip = wp2putils.p2p_go_ip(gc_dut)
+        wp2putils.p2p_connection_ping_test(gc_dut, go_ip)
+        # Trigger disconnect.
+        p2p_utils.remove_group_and_verify_disconnected(
+            client, group_owner, is_group_negotiation=False
+        )
+        time.sleep(_DEFAULT_FUNCTION_SWITCH_TIME)
+
+if __name__ == '__main__':
+  test_runner.main()
+
diff --git a/tests/hostsidetests/multidevices/test/direct/integration/wifi_p2p_lib.py b/tests/hostsidetests/multidevices/test/direct/integration/wifi_p2p_lib.py
new file mode 100644
index 0000000..566145c
--- /dev/null
+++ b/tests/hostsidetests/multidevices/test/direct/integration/wifi_p2p_lib.py
@@ -0,0 +1,221 @@
+"""WiFi P2P library for multi-devices tests."""
+#  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
+
+import datetime
+import time
+
+from direct import constants
+from direct import p2p_utils
+from mobly import asserts
+from mobly.controllers import android_device
+from mobly.controllers.android_device_lib import adb
+
+_DEFAULT_TIMEOUT = datetime.timedelta(seconds=30)
+_DEFAULT_SLEEPTIME = 5
+
+P2P_CONNECT_NEGOTIATION = 0
+P2P_CONNECT_JOIN = 1
+P2P_CONNECT_INVITATION = 2
+
+
+# Trigger p2p connect to device_go from device_gc.
+def p2p_connect(
+    device_gc: p2p_utils.DeviceState,
+    device_go: p2p_utils.DeviceState,
+    wps_setup,
+    p2p_connect_type=P2P_CONNECT_NEGOTIATION,
+    go_ad=None,
+):
+  """Trigger p2p connect to ad2 from ad1.
+
+  Args:
+      device_gc: The android device (Client)
+      device_go: The android device (GO)
+      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)
+  )
+  if p2p_connect_type == P2P_CONNECT_INVITATION:
+    if go_ad is None:
+      go_ad = device_gc
+    p2p_utils.discover_p2p_peer(device_gc, device_go)
+    # GO might be another peer, so ad2 needs to find it first.
+    p2p_utils.discover_group_owner(
+        client=device_go, group_owner_address=go_ad.p2p_device.device_address
+    )
+  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
+    )
+    asserts.assert_true(
+        peer_p2p_device.is_group_owner,
+        f"P2p device {peer_p2p_device} should be group owner.",
+    )
+  else:
+    p2p_utils.discover_p2p_peer(device_gc, device_go)
+  time.sleep(_DEFAULT_SLEEPTIME)
+  device_gc.ad.log.info(
+      'from device1: %s -> device2: %s',
+      device_gc.p2p_device.device_address,
+      device_go.p2p_device.device_address,
+  )
+  p2p_config = constants.WifiP2pConfig(
+      device_address=device_go.p2p_device.device_address,
+      wps_setup=wps_setup,
+  )
+  p2p_utils.p2p_connect(device_gc, device_go, p2p_config)
+
+
+def is_go(ad):
+  """Check an Android p2p role is Go or not.
+
+  Args:
+      ad: The android device
+
+  Returns:
+      True: An Android device is p2p go
+      False: An Android device is p2p gc
+  """
+  callback_handler = ad.wifi.wifiP2pRequestConnectionInfo()
+  event = callback_handler.waitAndGet(
+      event_name=constants.ON_CONNECTION_INFO_AVAILABLE,
+      timeout=_DEFAULT_TIMEOUT.total_seconds(),
+  )
+  if event.data['isGroupOwner']:
+    return True
+  return False
+
+
+def p2p_go_ip(ad):
+  """Get Group Owner IP address.
+
+  Args:
+      ad: The android device
+
+  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(),
+  )
+  ip = result.data['groupOwnerHostAddress'].replace('/', '')
+  ad.log.info('p2p go ip: %s' % ip)
+  return ip
+
+
+def p2p_disconnect(ad):
+  """Invoke an Android device removeGroup to trigger p2p disconnect.
+
+  Args:
+      ad: The android device
+  """
+  ad.log.debug('P2p Disconnect')
+  try:
+    ad.wifi.wifiP2pStopPeerDiscovery()
+    ad.wifi.wifiP2pCancelConnect()
+    ad.wifi.wifiP2pRemoveGroup()
+  finally:
+    # Make sure to call `p2pClose`, otherwise `_setup_wifi_p2p` won't be
+    # able to run again.
+    ad.wifi.p2pClose()
+
+
+def p2p_connection_ping_test(dut: android_device.AndroidDevice, peer_ip: str):
+  """Run a ping over the specified device/link.
+
+  Args:
+      dut: Device on which to execute ping6.
+      peer_ip: Scoped IPv4 address of the peer to ping.
+  """
+  cmd = 'ping -c 3 -W 1 %s' % peer_ip
+  try:
+    dut.log.info(cmd)
+    results = dut.adb.shell(cmd)
+  except adb.AdbError:
+    time.sleep(1)
+    dut.log.info('CMD RETRY: %s', cmd)
+    results = dut.adb.shell(cmd)
+
+  dut.log.info(results)
+
+
+class WifiP2PEnums:
+  """Enums for WifiP2p."""
+
+  class WifiP2pConfig:
+    DEVICEADDRESS_KEY = 'deviceAddress'
+    WPSINFO_KEY = 'wpsInfo'
+    GO_INTENT_KEY = 'groupOwnerIntent'
+    NETID_KEY = 'netId'
+    NETWORK_NAME = 'networkName'
+    PASSPHRASE = 'passphrase'
+    GROUP_BAND = 'groupOwnerBand'
+
+  class WpsInfo:
+    WPS_SETUP_KEY = 'setup'
+    BSSID_KEY = 'BSSID'
+    WPS_PIN_KEY = 'pin'
+    WIFI_WPS_INFO_PBC = 0
+    WIFI_WPS_INFO_DISPLAY = 1
+    WIFI_WPS_INFO_KEYPAD = 2
+    WIFI_WPS_INFO_LABEL = 3
+    WIFI_WPS_INFO_INVALID = 4
+
+  class WifiP2pServiceInfo:
+    # Macros for wifi p2p.
+    WIFI_P2P_SERVICE_TYPE_ALL = 0
+    WIFI_P2P_SERVICE_TYPE_BONJOUR = 1
+    WIFI_P2P_SERVICE_TYPE_UPNP = 2
+    WIFI_P2P_SERVICE_TYPE_VENDOR_SPECIFIC = 255
+
+  class WifiP2pDnsSdServiceResponse:
+    InstanceName = ''
+    RegistrationType = ''
+    FullDomainName = ''
+    TxtRecordMap = {}
+
+    def __init__(self):
+      pass
+
+    def toString(self):
+      return (
+          self.InstanceName
+          + self.RegistrationType
+          + (self.FullDomainName + str(self.TxtRecordMap))
+      )