Merge "[WIFICOND] Formalize the wificond AIDL interface"
diff --git a/api/system-current.txt b/api/system-current.txt
index 1a74f4b..77c40ea 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -6251,6 +6251,130 @@
 
 }
 
+package android.net.wifi.wificond {
+
+  public final class NativeScanResult implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public byte[] getBssid();
+    method @NonNull public java.util.BitSet getCapabilities();
+    method public int getFrequencyMhz();
+    method @NonNull public byte[] getInformationElements();
+    method @NonNull public java.util.List<android.net.wifi.wificond.RadioChainInfo> getRadioChainInfos();
+    method public int getSignalMbm();
+    method @NonNull public byte[] getSsid();
+    method public long getTsf();
+    method public boolean isAssociated();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.wificond.NativeScanResult> CREATOR;
+  }
+
+  public final class NativeWifiClient implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.wificond.NativeWifiClient> CREATOR;
+    field @NonNull public final byte[] macAddress;
+  }
+
+  public final class PnoNetwork implements android.os.Parcelable {
+    ctor public PnoNetwork();
+    method public int describeContents();
+    method @NonNull public int[] getFrequenciesMhz();
+    method @NonNull public byte[] getSsid();
+    method public boolean isHidden();
+    method public void setFrequenciesMhz(@NonNull int[]);
+    method public void setHidden(boolean);
+    method public void setSsid(@NonNull byte[]);
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.wificond.PnoNetwork> CREATOR;
+  }
+
+  public final class PnoSettings implements android.os.Parcelable {
+    ctor public PnoSettings();
+    method public int describeContents();
+    method public int getIntervalMillis();
+    method public int getMin2gRssiDbm();
+    method public int getMin5gRssiDbm();
+    method public int getMin6gRssiDbm();
+    method @NonNull public java.util.List<android.net.wifi.wificond.PnoNetwork> getPnoNetworks();
+    method public void setIntervalMillis(int);
+    method public void setMin2gRssiDbm(int);
+    method public void setMin5gRssiDbm(int);
+    method public void setMin6gRssiDbm(int);
+    method public void setPnoNetworks(@NonNull java.util.List<android.net.wifi.wificond.PnoNetwork>);
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.wificond.PnoSettings> CREATOR;
+  }
+
+  public final class RadioChainInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getChainId();
+    method public int getLevelDbm();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.wificond.RadioChainInfo> CREATOR;
+  }
+
+  public class WifiCondManager {
+    method public void abortScan(@NonNull String);
+    method public void enableVerboseLogging(boolean);
+    method @NonNull public int[] getChannelsMhzForBand(int);
+    method @NonNull public java.util.List<android.net.wifi.wificond.NativeScanResult> getScanResults(@NonNull String, int);
+    method @Nullable public android.net.wifi.wificond.WifiCondManager.TxPacketCounters getTxPacketCounters(@NonNull String);
+    method public boolean initialize(@NonNull Runnable);
+    method public boolean registerApCallback(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.wificond.WifiCondManager.SoftApCallback);
+    method public void sendMgmtFrame(@NonNull String, @NonNull byte[], int, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.wificond.WifiCondManager.SendMgmtFrameCallback);
+    method public boolean setupInterfaceForClientMode(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.wificond.WifiCondManager.ScanEventCallback, @NonNull android.net.wifi.wificond.WifiCondManager.ScanEventCallback);
+    method public boolean setupInterfaceForSoftApMode(@NonNull String);
+    method @Nullable public android.net.wifi.wificond.WifiCondManager.SignalPollResult signalPoll(@NonNull String);
+    method public boolean startPnoScan(@NonNull String, @NonNull android.net.wifi.wificond.PnoSettings, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.wificond.WifiCondManager.PnoScanRequestCallback);
+    method public boolean startScan(@NonNull String, int, @Nullable java.util.Set<java.lang.Integer>, @Nullable java.util.List<byte[]>);
+    method public boolean stopPnoScan(@NonNull String);
+    method public boolean tearDownClientInterface(@NonNull String);
+    method public boolean tearDownInterfaces();
+    method public boolean tearDownSoftApInterface(@NonNull String);
+    field public static final int SCAN_TYPE_PNO_SCAN = 1; // 0x1
+    field public static final int SCAN_TYPE_SINGLE_SCAN = 0; // 0x0
+    field public static final int SEND_MGMT_FRAME_ERROR_ALREADY_STARTED = 5; // 0x5
+    field public static final int SEND_MGMT_FRAME_ERROR_MCS_UNSUPPORTED = 2; // 0x2
+    field public static final int SEND_MGMT_FRAME_ERROR_NO_ACK = 3; // 0x3
+    field public static final int SEND_MGMT_FRAME_ERROR_TIMEOUT = 4; // 0x4
+    field public static final int SEND_MGMT_FRAME_ERROR_UNKNOWN = 1; // 0x1
+  }
+
+  public static interface WifiCondManager.PnoScanRequestCallback {
+    method public void onPnoRequestFailed();
+    method public void onPnoRequestSucceeded();
+  }
+
+  public static interface WifiCondManager.ScanEventCallback {
+    method public void onScanFailed();
+    method public void onScanResultReady();
+  }
+
+  public static interface WifiCondManager.SendMgmtFrameCallback {
+    method public void onAck(int);
+    method public void onFailure(int);
+  }
+
+  public static class WifiCondManager.SignalPollResult {
+    field public final int associationFrequencyMHz;
+    field public final int currentRssiDbm;
+    field public final int rxBitrateMbps;
+    field public final int txBitrateMbps;
+  }
+
+  public static interface WifiCondManager.SoftApCallback {
+    method public void onConnectedClientsChanged(@NonNull android.net.wifi.wificond.NativeWifiClient, boolean);
+    method public void onFailure();
+    method public void onSoftApChannelSwitched(int, int);
+  }
+
+  public static class WifiCondManager.TxPacketCounters {
+    field public final int txPacketFailed;
+    field public final int txPacketSucceeded;
+  }
+
+}
+
 package android.nfc {
 
   public final class NfcAdapter {
diff --git a/api/system-lint-baseline.txt b/api/system-lint-baseline.txt
index 9a635757..da0aae0 100644
--- a/api/system-lint-baseline.txt
+++ b/api/system-lint-baseline.txt
@@ -24,6 +24,11 @@
 ExecutorRegistration: android.net.wifi.p2p.WifiP2pManager#setWifiP2pChannels(android.net.wifi.p2p.WifiP2pManager.Channel, int, int, android.net.wifi.p2p.WifiP2pManager.ActionListener):
     Registration methods should have overload that accepts delivery Executor: `setWifiP2pChannels`
 
+HeavyBitSet: android.net.wifi.wificond.NativeScanResult#getCapabilities():
+    Type must not be heavy BitSet (method android.net.wifi.wificond.NativeScanResult.getCapabilities())
+PairedRegistration: android.net.wifi.wificond.WifiCondManager#registerApCallback(String, java.util.concurrent.Executor, android.net.wifi.wificond.WifiCondManager.SoftApCallback):
+    Found registerApCallback but not unregisterApCallback in android.net.wifi.wificond.WifiCondManager
+
 
 GenericException: android.app.prediction.AppPredictor#finalize():
     
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index d33c801..83e4b00 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -120,8 +120,8 @@
 import android.net.lowpan.LowpanManager;
 import android.net.nsd.INsdManager;
 import android.net.nsd.NsdManager;
-import android.net.wifi.WifiCondManager;
 import android.net.wifi.WifiFrameworkInitializer;
+import android.net.wifi.wificond.WifiCondManager;
 import android.nfc.NfcManager;
 import android.os.BatteryManager;
 import android.os.BatteryStats;
diff --git a/wifi/Android.bp b/wifi/Android.bp
index 08115ec..fb1f866 100644
--- a/wifi/Android.bp
+++ b/wifi/Android.bp
@@ -32,7 +32,6 @@
         // framework-wifi.jar. This is not a good idea, should move WifiNetworkScoreCache
         // to a separate package.
         "java/android/net/wifi/WifiNetworkScoreCache.java",
-        "java/android/net/wifi/WifiCondManager.java",
         "java/android/net/wifi/wificond/*.java",
         ":libwificond_ipc_aidl",
     ],
diff --git a/wifi/java/android/net/wifi/SoftApInfo.java b/wifi/java/android/net/wifi/SoftApInfo.java
index 375a977..24ed8ef 100644
--- a/wifi/java/android/net/wifi/SoftApInfo.java
+++ b/wifi/java/android/net/wifi/SoftApInfo.java
@@ -16,15 +16,12 @@
 
 package android.net.wifi;
 
-import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
 import java.util.Objects;
 
 /**
@@ -85,26 +82,12 @@
      */
     public static final int CHANNEL_WIDTH_160MHZ = 6;
 
-    /**
-     * @hide
-     */
-    @IntDef(prefix = { "CHANNEL_WIDTH_" }, value = {
-            CHANNEL_WIDTH_INVALID,
-            CHANNEL_WIDTH_20MHZ_NOHT,
-            CHANNEL_WIDTH_20MHZ,
-            CHANNEL_WIDTH_40MHZ,
-            CHANNEL_WIDTH_80MHZ,
-            CHANNEL_WIDTH_80MHZ_PLUS_MHZ,
-            CHANNEL_WIDTH_160MHZ,
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface Bandwidth {}
 
 
     /** The frequency which AP resides on.  */
     private int mFrequency = 0;
 
-    @Bandwidth
+    @WifiAnnotations.Bandwidth
     private int mBandwidth = CHANNEL_WIDTH_INVALID;
 
     /**
@@ -127,9 +110,9 @@
      *
      * @return One of {@link #CHANNEL_WIDTH_20MHZ}, {@link #CHANNEL_WIDTH_40MHZ},
      * {@link #CHANNEL_WIDTH_80MHZ}, {@link #CHANNEL_WIDTH_160MHZ},
-     * {@link #CHANNEL_WIDTH_80MHZ_PLUS_MHZ} or {@link #CHANNEL_WIDTH_UNKNOWN}.
+     * {@link #CHANNEL_WIDTH_80MHZ_PLUS_MHZ} or {@link #CHANNEL_WIDTH_INVALID}.
      */
-    @Bandwidth
+    @WifiAnnotations.Bandwidth
     public int getBandwidth() {
         return mBandwidth;
     }
@@ -138,7 +121,7 @@
      * Set AP Channel bandwidth.
      * @hide
      */
-    public void setBandwidth(@Bandwidth int bandwidth) {
+    public void setBandwidth(@WifiAnnotations.Bandwidth int bandwidth) {
         mBandwidth = bandwidth;
     }
 
diff --git a/wifi/java/android/net/wifi/WifiAnnotations.java b/wifi/java/android/net/wifi/WifiAnnotations.java
index 4a7dee1..9223d28 100644
--- a/wifi/java/android/net/wifi/WifiAnnotations.java
+++ b/wifi/java/android/net/wifi/WifiAnnotations.java
@@ -48,4 +48,16 @@
             WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY,
             WifiScanner.WIFI_BAND_6_GHZ})
     public @interface WifiBandBasic {}
+
+    @IntDef(prefix = { "CHANNEL_WIDTH_" }, value = {
+            SoftApInfo.CHANNEL_WIDTH_INVALID,
+            SoftApInfo.CHANNEL_WIDTH_20MHZ_NOHT,
+            SoftApInfo.CHANNEL_WIDTH_20MHZ,
+            SoftApInfo.CHANNEL_WIDTH_40MHZ,
+            SoftApInfo.CHANNEL_WIDTH_80MHZ,
+            SoftApInfo.CHANNEL_WIDTH_80MHZ_PLUS_MHZ,
+            SoftApInfo.CHANNEL_WIDTH_160MHZ,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Bandwidth {}
 }
diff --git a/wifi/java/android/net/wifi/wificond/NativeScanResult.java b/wifi/java/android/net/wifi/wificond/NativeScanResult.java
index ff8e935..6ed1708 100644
--- a/wifi/java/android/net/wifi/wificond/NativeScanResult.java
+++ b/wifi/java/android/net/wifi/wificond/NativeScanResult.java
@@ -16,46 +16,163 @@
 
 package android.net.wifi.wificond;
 
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import java.util.ArrayList;
 import java.util.BitSet;
 import java.util.List;
 
 /**
- * ScanResult from wificond
+ * Raw scan result data from the wificond daemon.
  *
  * @hide
  */
-public class NativeScanResult implements Parcelable {
+@SystemApi
+public final class NativeScanResult implements Parcelable {
     private static final int CAPABILITY_SIZE = 16;
 
+    /** @hide */
+    @VisibleForTesting
     public byte[] ssid;
+    /** @hide */
+    @VisibleForTesting
     public byte[] bssid;
+    /** @hide */
+    @VisibleForTesting
     public byte[] infoElement;
+    /** @hide */
+    @VisibleForTesting
     public int frequency;
+    /** @hide */
+    @VisibleForTesting
     public int signalMbm;
+    /** @hide */
+    @VisibleForTesting
     public long tsf;
+    /** @hide */
+    @VisibleForTesting
     public BitSet capability;
+    /** @hide */
+    @VisibleForTesting
     public boolean associated;
+    /** @hide */
+    @VisibleForTesting
     public List<RadioChainInfo> radioChainInfos;
 
-    /** public constructor */
-    public NativeScanResult() { }
-
-    /** copy constructor */
-    public NativeScanResult(NativeScanResult source) {
-        ssid = source.ssid.clone();
-        bssid = source.bssid.clone();
-        infoElement = source.infoElement.clone();
-        frequency = source.frequency;
-        signalMbm = source.signalMbm;
-        tsf = source.tsf;
-        capability = (BitSet) source.capability.clone();
-        associated = source.associated;
+    /**
+     * Returns the SSID raw byte array of the AP represented by this scan result.
+     *
+     * @return A byte array.
+     */
+    @NonNull public byte[] getSsid() {
+        return ssid;
     }
 
+    /**
+     * Returns raw bytes representing the MAC address (BSSID) of the AP represented by this scan
+     * result.
+     *
+     * @return a byte array, possibly null or containing the incorrect number of bytes for a MAC
+     * address.
+     */
+    @NonNull public byte[] getBssid() {
+        return bssid;
+    }
+
+    /**
+     * Returns the raw bytes of the information element advertised by the AP represented by this
+     * scan result.
+     *
+     * @return A byte array, possibly null or containing an invalid TLV configuration.
+     */
+    @NonNull public byte[] getInformationElements() {
+        return infoElement;
+    }
+
+    /**
+     * Returns the frequency (in MHz) on which the AP represented by this scan result was observed.
+     *
+     * @return The frequency in MHz.
+     */
+    public int getFrequencyMhz() {
+        return frequency;
+    }
+
+    /**
+     * Return the signal strength of probe response/beacon in (100 * dBm).
+     *
+     * @return Signal strenght in (100 * dBm).
+     */
+    public int getSignalMbm() {
+        return signalMbm;
+    }
+
+    /**
+     * Return the TSF (Timing Synchronization Function) of the received probe response/beacon.
+     * @return
+     */
+    public long getTsf() {
+        return tsf;
+    }
+
+    /**
+     * Return a boolean indicating whether or not we're associated to the AP represented by this
+     * scan result.
+     *
+     * @return A boolean indicating association.
+     */
+    public boolean isAssociated() {
+        return associated;
+    }
+
+    /**
+     *  Returns the capabilities of the AP repseresented by this scan result as advertised in the
+     *  received probe response or beacon.
+     *
+     *  This is a bit mask describing the capabilities of a BSS. See IEEE Std 802.11: 8.4.1.4:
+     *    Bit 0 - ESS
+     *    Bit 1 - IBSS
+     *    Bit 2 - CF Pollable
+     *    Bit 3 - CF-Poll Request
+     *    Bit 4 - Privacy
+     *    Bit 5 - Short Preamble
+     *    Bit 6 - PBCC
+     *    Bit 7 - Channel Agility
+     *    Bit 8 - Spectrum Mgmt
+     *    Bit 9 - QoS
+     *    Bit 10 - Short Slot Time
+     *    Bit 11 - APSD
+     *    Bit 12 - Radio Measurement
+     *    Bit 13 - DSSS-OFDM
+     *    Bit 14 - Delayed Block Ack
+     *    Bit 15 - Immediate Block Ack
+     *
+     * @return a bit mask of capabilities.
+     */
+    @NonNull public BitSet getCapabilities() {
+        return capability;
+    }
+
+    /**
+     * Returns details of the signal received on each radio chain for the AP represented by this
+     * scan result in a list of {@link RadioChainInfo} elements.
+     *
+     * @return A list of {@link RadioChainInfo} - possibly empty in case of error.
+     */
+    @NonNull public List<RadioChainInfo> getRadioChainInfos() {
+        return radioChainInfos;
+    }
+
+    /**
+     * @hide
+     */
+    public NativeScanResult() { }
+
     /** implement Parcelable interface */
     @Override
     public int describeContents() {
@@ -64,7 +181,7 @@
 
     /** implement Parcelable interface */
     @Override
-    public void writeToParcel(Parcel out, int flags) {
+    public void writeToParcel(@NonNull Parcel out, int flags) {
         out.writeByteArray(ssid);
         out.writeByteArray(bssid);
         out.writeByteArray(infoElement);
@@ -83,14 +200,23 @@
     }
 
     /** implement Parcelable interface */
-    public static final Parcelable.Creator<NativeScanResult> CREATOR =
+    @NonNull public static final Parcelable.Creator<NativeScanResult> CREATOR =
             new Parcelable.Creator<NativeScanResult>() {
         @Override
         public NativeScanResult createFromParcel(Parcel in) {
             NativeScanResult result = new NativeScanResult();
             result.ssid = in.createByteArray();
+            if (result.ssid == null) {
+                result.ssid = new byte[0];
+            }
             result.bssid = in.createByteArray();
+            if (result.bssid == null) {
+                result.bssid = new byte[0];
+            }
             result.infoElement = in.createByteArray();
+            if (result.infoElement == null) {
+                result.infoElement = new byte[0];
+            }
             result.frequency = in.readInt();
             result.signalMbm = in.readInt();
             result.tsf = in.readLong();
diff --git a/wifi/java/android/net/wifi/wificond/NativeWifiClient.java b/wifi/java/android/net/wifi/wificond/NativeWifiClient.java
index 4994ebd..554f929 100644
--- a/wifi/java/android/net/wifi/wificond/NativeWifiClient.java
+++ b/wifi/java/android/net/wifi/wificond/NativeWifiClient.java
@@ -16,21 +16,32 @@
 
 package android.net.wifi.wificond;
 
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
 import java.util.Arrays;
 
 /**
- * NativeWifiClient for wificond
+ * Structure providing information about clients (STAs) associated with a SoftAp.
  *
  * @hide
  */
-public class NativeWifiClient implements Parcelable {
-    public byte[] macAddress;
+@SystemApi
+public final class NativeWifiClient implements Parcelable {
+    /**
+     * The raw bytes of the MAC address of the client (STA) represented by this object.
+     */
+    @NonNull public final byte[] macAddress;
 
-    /** public constructor */
-    public NativeWifiClient() { }
+    /**
+     * public constructor
+     * @hide
+     */
+    public NativeWifiClient(@NonNull byte[] macAddress) {
+        this.macAddress = macAddress;
+    }
 
     /** override comparator */
     @Override
@@ -60,18 +71,20 @@
      * |flag| is ignored.
      */
     @Override
-    public void writeToParcel(Parcel out, int flags) {
+    public void writeToParcel(@NonNull Parcel out, int flags) {
         out.writeByteArray(macAddress);
     }
 
     /** implement Parcelable interface */
-    public static final Parcelable.Creator<NativeWifiClient> CREATOR =
+    @NonNull public static final Parcelable.Creator<NativeWifiClient> CREATOR =
             new Parcelable.Creator<NativeWifiClient>() {
                 @Override
                 public NativeWifiClient createFromParcel(Parcel in) {
-                    NativeWifiClient result = new NativeWifiClient();
-                    result.macAddress = in.createByteArray();
-                    return result;
+                    byte[] macAddress = in.createByteArray();
+                    if (macAddress == null) {
+                        macAddress = new byte[0];
+                    }
+                    return new NativeWifiClient(macAddress);
                 }
 
                 @Override
diff --git a/wifi/java/android/net/wifi/wificond/PnoNetwork.java b/wifi/java/android/net/wifi/wificond/PnoNetwork.java
index f923fd3..ca0b1cf 100644
--- a/wifi/java/android/net/wifi/wificond/PnoNetwork.java
+++ b/wifi/java/android/net/wifi/wificond/PnoNetwork.java
@@ -16,6 +16,8 @@
 
 package android.net.wifi.wificond;
 
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -23,17 +25,85 @@
 import java.util.Objects;
 
 /**
- * PnoNetwork for wificond
+ * Configuration for a PNO (preferred network offload) network used in {@link PnoSettings}. A PNO
+ * network allows configuration of a specific network to search for.
  *
  * @hide
  */
-public class PnoNetwork implements Parcelable {
+@SystemApi
+public final class PnoNetwork implements Parcelable {
+    private boolean mIsHidden;
+    private byte[] mSsid;
+    private int[] mFrequencies;
 
-    public boolean isHidden;
-    public byte[] ssid;
-    public int[] frequencies;
+    /**
+     * Indicates whether the PNO network configuration is for a hidden SSID - i.e. a network which
+     * does not broadcast its SSID and must be queried explicitly.
+     *
+     * @return True if the configuration is for a hidden network, false otherwise.
+     */
+    public boolean isHidden() {
+        return mIsHidden;
+    }
 
-    /** public constructor */
+    /**
+     * Configure whether the PNO network configuration is for a hidden SSID - i.e. a network which
+     * does not broadcast its SSID and must be queried explicitly.
+     *
+     * @param isHidden True if the configuration is for a hidden network, false otherwise.
+     */
+    public void setHidden(boolean isHidden) {
+        mIsHidden = isHidden;
+    }
+
+    /**
+     * Get the raw bytes for the SSID of the PNO network being scanned for.
+     *
+     * @return A byte array.
+     */
+    @NonNull public byte[] getSsid() {
+        return mSsid;
+    }
+
+    /**
+     * Set the raw bytes for the SSID of the PNO network being scanned for.
+     *
+     * @param ssid A byte array.
+     */
+    public void setSsid(@NonNull byte[] ssid) {
+        if (ssid == null) {
+            throw new IllegalArgumentException("null argument");
+        }
+        this.mSsid = ssid;
+    }
+
+    /**
+     * Get the frequencies (in MHz) on which to PNO scan for the current network is being searched
+     * for. A null return (i.e. no frequencies configured) indicates that the network is search for
+     * on all supported frequencies.
+     *
+     * @return A array of frequencies (in MHz), a null indicates no configured frequencies.
+     */
+    @NonNull public int[] getFrequenciesMhz() {
+        return mFrequencies;
+    }
+
+    /**
+     * Set the frequencies (in MHz) on which to PNO scan for the current network is being searched
+     * for. A null configuration (i.e. no frequencies configured) indicates that the network is
+     * search for on all supported frequencies.
+     *
+     * @param frequenciesMhz an array of frequencies (in MHz), null indicating no configured
+     *                       frequencies.
+     */
+    public void setFrequenciesMhz(@NonNull int[] frequenciesMhz) {
+        if (frequenciesMhz == null) {
+            throw new IllegalArgumentException("null argument");
+        }
+        this.mFrequencies = frequenciesMhz;
+    }
+
+    /** Construct an uninitialized PnoNetwork object */
     public PnoNetwork() { }
 
     /** override comparator */
@@ -44,18 +114,18 @@
             return false;
         }
         PnoNetwork network = (PnoNetwork) rhs;
-        return Arrays.equals(ssid, network.ssid)
-                && Arrays.equals(frequencies, network.frequencies)
-                && isHidden == network.isHidden;
+        return Arrays.equals(mSsid, network.mSsid)
+                && Arrays.equals(mFrequencies, network.mFrequencies)
+                && mIsHidden == network.mIsHidden;
     }
 
     /** override hash code */
     @Override
     public int hashCode() {
         return Objects.hash(
-                isHidden,
-                Arrays.hashCode(ssid),
-                Arrays.hashCode(frequencies));
+                mIsHidden,
+                Arrays.hashCode(mSsid),
+                Arrays.hashCode(mFrequencies));
     }
 
     /** implement Parcelable interface */
@@ -69,21 +139,27 @@
      * |flag| is ignored.
      */
     @Override
-    public void writeToParcel(Parcel out, int flags) {
-        out.writeInt(isHidden ? 1 : 0);
-        out.writeByteArray(ssid);
-        out.writeIntArray(frequencies);
+    public void writeToParcel(@NonNull Parcel out, int flags) {
+        out.writeInt(mIsHidden ? 1 : 0);
+        out.writeByteArray(mSsid);
+        out.writeIntArray(mFrequencies);
     }
 
     /** implement Parcelable interface */
-    public static final Parcelable.Creator<PnoNetwork> CREATOR =
+    @NonNull public static final Parcelable.Creator<PnoNetwork> CREATOR =
             new Parcelable.Creator<PnoNetwork>() {
         @Override
         public PnoNetwork createFromParcel(Parcel in) {
             PnoNetwork result = new PnoNetwork();
-            result.isHidden = in.readInt() != 0 ? true : false;
-            result.ssid = in.createByteArray();
-            result.frequencies = in.createIntArray();
+            result.mIsHidden = in.readInt() != 0 ? true : false;
+            result.mSsid = in.createByteArray();
+            if (result.mSsid == null) {
+                result.mSsid = new byte[0];
+            }
+            result.mFrequencies = in.createIntArray();
+            if (result.mFrequencies == null) {
+                result.mFrequencies = new int[0];
+            }
             return result;
         }
 
diff --git a/wifi/java/android/net/wifi/wificond/PnoSettings.java b/wifi/java/android/net/wifi/wificond/PnoSettings.java
index 96cf24f..57c9ca5 100644
--- a/wifi/java/android/net/wifi/wificond/PnoSettings.java
+++ b/wifi/java/android/net/wifi/wificond/PnoSettings.java
@@ -16,27 +16,130 @@
 
 package android.net.wifi.wificond;
 
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
 import java.util.ArrayList;
+import java.util.List;
 import java.util.Objects;
 
 /**
- * PnoSettings for wificond
+ * Configuration for a PNO (preferred network offload). A mechanism by which scans are offloaded
+ * from the host device to the Wi-Fi chip.
  *
  * @hide
  */
-public class PnoSettings implements Parcelable {
-    public int intervalMs;
-    public int min2gRssi;
-    public int min5gRssi;
-    public int min6gRssi;
-    public ArrayList<PnoNetwork> pnoNetworks;
+@SystemApi
+public final class PnoSettings implements Parcelable {
+    private int mIntervalMs;
+    private int mMin2gRssi;
+    private int mMin5gRssi;
+    private int mMin6gRssi;
+    private List<PnoNetwork> mPnoNetworks;
 
-    /** public constructor */
+    /** Construct an uninitialized PnoSettings object */
     public PnoSettings() { }
 
+    /**
+     * Get the requested PNO scan interval in milliseconds.
+     *
+     * @return An interval in milliseconds.
+     */
+    public int getIntervalMillis() {
+        return mIntervalMs;
+    }
+
+    /**
+     * Set the requested PNO scan interval in milliseconds.
+     *
+     * @param intervalMs An interval in milliseconds.
+     */
+    public void setIntervalMillis(int intervalMs) {
+        this.mIntervalMs = intervalMs;
+    }
+
+    /**
+     * Get the requested minimum RSSI threshold (in dBm) for APs to report in scan results in the
+     * 2.4GHz band.
+     *
+     * @return An RSSI value in dBm.
+     */
+    public int getMin2gRssiDbm() {
+        return mMin2gRssi;
+    }
+
+    /**
+     * Set the requested minimum RSSI threshold (in dBm) for APs to report in scan scan results in
+     * the 2.4GHz band.
+     *
+     * @param min2gRssiDbm An RSSI value in dBm.
+     */
+    public void setMin2gRssiDbm(int min2gRssiDbm) {
+        this.mMin2gRssi = min2gRssiDbm;
+    }
+
+    /**
+     * Get the requested minimum RSSI threshold (in dBm) for APs to report in scan results in the
+     * 5GHz band.
+     *
+     * @return An RSSI value in dBm.
+     */
+    public int getMin5gRssiDbm() {
+        return mMin5gRssi;
+    }
+
+    /**
+     * Set the requested minimum RSSI threshold (in dBm) for APs to report in scan scan results in
+     * the 5GHz band.
+     *
+     * @param min5gRssiDbm An RSSI value in dBm.
+     */
+    public void setMin5gRssiDbm(int min5gRssiDbm) {
+        this.mMin5gRssi = min5gRssiDbm;
+    }
+
+    /**
+     * Get the requested minimum RSSI threshold (in dBm) for APs to report in scan results in the
+     * 6GHz band.
+     *
+     * @return An RSSI value in dBm.
+     */
+    public int getMin6gRssiDbm() {
+        return mMin6gRssi;
+    }
+
+    /**
+     * Set the requested minimum RSSI threshold (in dBm) for APs to report in scan scan results in
+     * the 6GHz band.
+     *
+     * @param min6gRssiDbm An RSSI value in dBm.
+     */
+    public void setMin6gRssiDbm(int min6gRssiDbm) {
+        this.mMin6gRssi = min6gRssiDbm;
+    }
+
+    /**
+     * Return the configured list of specific networks to search for in a PNO scan.
+     *
+     * @return A list of {@link PnoNetwork} objects, possibly empty if non configured.
+     */
+    @NonNull public List<PnoNetwork> getPnoNetworks() {
+        return mPnoNetworks;
+    }
+
+    /**
+     * Set the list of specified networks to scan for in a PNO scan. The networks (APs) are
+     * specified using {@link PnoNetwork}s. An empty list indicates that all networks are scanned
+     * for.
+     *
+     * @param pnoNetworks A (possibly empty) list of {@link PnoNetwork} objects.
+     */
+    public void setPnoNetworks(@NonNull List<PnoNetwork> pnoNetworks) {
+        this.mPnoNetworks = pnoNetworks;
+    }
+
     /** override comparator */
     @Override
     public boolean equals(Object rhs) {
@@ -48,17 +151,17 @@
         if (settings == null) {
             return false;
         }
-        return intervalMs == settings.intervalMs
-                && min2gRssi == settings.min2gRssi
-                && min5gRssi == settings.min5gRssi
-                && min6gRssi == settings.min6gRssi
-                && pnoNetworks.equals(settings.pnoNetworks);
+        return mIntervalMs == settings.mIntervalMs
+                && mMin2gRssi == settings.mMin2gRssi
+                && mMin5gRssi == settings.mMin5gRssi
+                && mMin6gRssi == settings.mMin6gRssi
+                && mPnoNetworks.equals(settings.mPnoNetworks);
     }
 
     /** override hash code */
     @Override
     public int hashCode() {
-        return Objects.hash(intervalMs, min2gRssi, min5gRssi, min6gRssi, pnoNetworks);
+        return Objects.hash(mIntervalMs, mMin2gRssi, mMin5gRssi, mMin6gRssi, mPnoNetworks);
     }
 
     /** implement Parcelable interface */
@@ -72,27 +175,27 @@
      * |flag| is ignored.
      **/
     @Override
-    public void writeToParcel(Parcel out, int flags) {
-        out.writeInt(intervalMs);
-        out.writeInt(min2gRssi);
-        out.writeInt(min5gRssi);
-        out.writeInt(min6gRssi);
-        out.writeTypedList(pnoNetworks);
+    public void writeToParcel(@NonNull Parcel out, int flags) {
+        out.writeInt(mIntervalMs);
+        out.writeInt(mMin2gRssi);
+        out.writeInt(mMin5gRssi);
+        out.writeInt(mMin6gRssi);
+        out.writeTypedList(mPnoNetworks);
     }
 
     /** implement Parcelable interface */
-    public static final Parcelable.Creator<PnoSettings> CREATOR =
+    @NonNull public static final Parcelable.Creator<PnoSettings> CREATOR =
             new Parcelable.Creator<PnoSettings>() {
         @Override
         public PnoSettings createFromParcel(Parcel in) {
             PnoSettings result = new PnoSettings();
-            result.intervalMs = in.readInt();
-            result.min2gRssi = in.readInt();
-            result.min5gRssi = in.readInt();
-            result.min6gRssi = in.readInt();
+            result.mIntervalMs = in.readInt();
+            result.mMin2gRssi = in.readInt();
+            result.mMin5gRssi = in.readInt();
+            result.mMin6gRssi = in.readInt();
 
-            result.pnoNetworks = new ArrayList<PnoNetwork>();
-            in.readTypedList(result.pnoNetworks, PnoNetwork.CREATOR);
+            result.mPnoNetworks = new ArrayList<>();
+            in.readTypedList(result.mPnoNetworks, PnoNetwork.CREATOR);
 
             return result;
         }
diff --git a/wifi/java/android/net/wifi/wificond/RadioChainInfo.java b/wifi/java/android/net/wifi/wificond/RadioChainInfo.java
index 2b03450..64102dd 100644
--- a/wifi/java/android/net/wifi/wificond/RadioChainInfo.java
+++ b/wifi/java/android/net/wifi/wificond/RadioChainInfo.java
@@ -16,26 +16,52 @@
 
 package android.net.wifi.wificond;
 
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import java.util.Objects;
 
 /**
- * RadioChainInfo for wificond
+ * A class representing the radio chains of the Wi-Fi modems. Use to provide raw information about
+ * signals received on different radio chains.
  *
  * @hide
  */
-public class RadioChainInfo implements Parcelable {
+@SystemApi
+public final class RadioChainInfo implements Parcelable {
     private static final String TAG = "RadioChainInfo";
 
+    /** @hide */
+    @VisibleForTesting
     public int chainId;
+    /** @hide */
+    @VisibleForTesting
     public int level;
 
+    /**
+     * Return an identifier for this radio chain. This is an arbitrary ID which is consistent for
+     * the same device.
+     *
+     * @return The radio chain ID.
+     */
+    public int getChainId() {
+        return chainId;
+    }
 
-    /** public constructor */
-    public RadioChainInfo() { }
+    /**
+     * Returns the detected signal level on this radio chain in dBm (aka RSSI).
+     *
+     * @return A signal level in dBm.
+     */
+    public int getLevelDbm() {
+        return level;
+    }
 
+    /** @hide */
     public RadioChainInfo(int chainId, int level) {
         this.chainId = chainId;
         this.level = level;
@@ -73,23 +99,20 @@
      * |flags| is ignored.
      */
     @Override
-    public void writeToParcel(Parcel out, int flags) {
+    public void writeToParcel(@NonNull Parcel out, int flags) {
         out.writeInt(chainId);
         out.writeInt(level);
     }
 
     /** implement Parcelable interface */
-    public static final Parcelable.Creator<RadioChainInfo> CREATOR =
+    @NonNull public static final Parcelable.Creator<RadioChainInfo> CREATOR =
             new Parcelable.Creator<RadioChainInfo>() {
         /**
          * Caller is responsible for providing a valid parcel.
          */
         @Override
         public RadioChainInfo createFromParcel(Parcel in) {
-            RadioChainInfo result = new RadioChainInfo();
-            result.chainId = in.readInt();
-            result.level = in.readInt();
-            return result;
+            return new RadioChainInfo(in.readInt(), in.readInt());
         }
 
         @Override
diff --git a/wifi/java/android/net/wifi/WifiCondManager.java b/wifi/java/android/net/wifi/wificond/WifiCondManager.java
similarity index 61%
rename from wifi/java/android/net/wifi/WifiCondManager.java
rename to wifi/java/android/net/wifi/wificond/WifiCondManager.java
index c05ba34..94f1212 100644
--- a/wifi/java/android/net/wifi/WifiCondManager.java
+++ b/wifi/java/android/net/wifi/wificond/WifiCondManager.java
@@ -14,18 +14,27 @@
  * limitations under the License.
  */
 
-package android.net.wifi;
+package android.net.wifi.wificond;
 
+import android.annotation.CallbackExecutor;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.annotation.SystemService;
 import android.app.AlarmManager;
 import android.content.Context;
-import android.net.wifi.wificond.ChannelSettings;
-import android.net.wifi.wificond.HiddenNetwork;
-import android.net.wifi.wificond.NativeScanResult;
-import android.net.wifi.wificond.NativeWifiClient;
-import android.net.wifi.wificond.PnoSettings;
-import android.net.wifi.wificond.SingleScanSettings;
+import android.net.wifi.IApInterface;
+import android.net.wifi.IApInterfaceEventCallback;
+import android.net.wifi.IClientInterface;
+import android.net.wifi.IPnoScanEvent;
+import android.net.wifi.IScanEvent;
+import android.net.wifi.ISendMgmtFrameEvent;
+import android.net.wifi.IWifiScannerImpl;
+import android.net.wifi.IWificond;
+import android.net.wifi.SoftApInfo;
+import android.net.wifi.WifiAnnotations;
+import android.net.wifi.WifiScanner;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
@@ -44,37 +53,48 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.Executor;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
- * This class provides methods for WifiNative to send control commands to wificond.
- * NOTE: This class should only be used from WifiNative.
+ * This class encapsulates the interface the wificond daemon presents to the Wi-Fi framework. The
+ * interface is only for use by the Wi-Fi framework and access is protected by SELinux permissions.
+ *
  * @hide
  */
-public class WifiCondManager implements IBinder.DeathRecipient {
+@SystemApi
+@SystemService(Context.WIFI_COND_SERVICE)
+public class WifiCondManager {
     private static final String TAG = "WifiCondManager";
     private boolean mVerboseLoggingEnabled = false;
 
     /**
-     * The {@link #sendMgmtFrame(String, byte[], SendMgmtFrameCallback, int) sendMgmtFrame()}
+     * The {@link #sendMgmtFrame(String, byte[], int, Executor, SendMgmtFrameCallback)}
      * timeout, in milliseconds, after which
      * {@link SendMgmtFrameCallback#onFailure(int)} will be called with reason
      * {@link #SEND_MGMT_FRAME_ERROR_TIMEOUT}.
      */
-    public static final int SEND_MGMT_FRAME_TIMEOUT_MS = 1000;
+    private static final int SEND_MGMT_FRAME_TIMEOUT_MS = 1000;
 
     private static final String TIMEOUT_ALARM_TAG = TAG + " Send Management Frame Timeout";
 
+    /** @hide */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(prefix = {"SCAN_TYPE_"},
             value = {SCAN_TYPE_SINGLE_SCAN,
                     SCAN_TYPE_PNO_SCAN})
     public @interface ScanResultType {}
 
-    /** Get scan results for a single scan */
+    /**
+     * Specifies a scan type: single scan initiated by the framework. Can be used in
+     * {@link #getScanResults(String, int)} to specify the type of scan result to fetch.
+     */
     public static final int SCAN_TYPE_SINGLE_SCAN = 0;
 
-    /** Get scan results for Pno Scan */
+    /**
+     * Specifies a scan type: PNO scan. Can be used in {@link #getScanResults(String, int)} to
+     * specify the type of scan result to fetch.
+     */
     public static final int SCAN_TYPE_PNO_SCAN = 1;
 
     private AlarmManager mAlarmManager;
@@ -95,11 +115,12 @@
     private AtomicBoolean mSendMgmtFrameInProgress = new AtomicBoolean(false);
 
     /**
-     * Interface for a callback to be used to handle scan results.
+     * Interface used when waiting for scans to be completed (with results).
      */
     public interface ScanEventCallback {
         /**
-         * Called when scan results are available.
+         * Called when scan results are available. Scans results should then be obtained from
+         * {@link #getScanResults(String, int)}.
          */
         void onScanResultReady();
 
@@ -110,11 +131,14 @@
     }
 
     /**
-     * Interface for a callback to provide information about PNO scan request.
+     * Interface for a callback to provide information about PNO scan request requested with
+     * {@link #startPnoScan(String, PnoSettings, Executor, PnoScanRequestCallback)}. Note that the
+     * callback are for the status of the request - not the scan itself. The results of the scan
+     * are returned with {@link ScanEventCallback}.
      */
     public interface PnoScanRequestCallback {
         /**
-         * Called when the PNO scan is requested.
+         * Called when a PNO scan request has been successfully submitted.
          */
         void onPnoRequestSucceeded();
 
@@ -125,73 +149,116 @@
     }
 
     private class ScanEventHandler extends IScanEvent.Stub {
+        private Executor mExecutor;
         private ScanEventCallback mCallback;
 
-        ScanEventHandler(@NonNull ScanEventCallback callback) {
+        ScanEventHandler(@NonNull Executor executor, @NonNull ScanEventCallback callback) {
+            mExecutor = executor;
             mCallback = callback;
         }
 
         @Override
         public void OnScanResultReady() {
             Log.d(TAG, "Scan result ready event");
-            mCallback.onScanResultReady();
+            Binder.clearCallingIdentity();
+            mExecutor.execute(() -> mCallback.onScanResultReady());
         }
 
         @Override
         public void OnScanFailed() {
             Log.d(TAG, "Scan failed event");
-            mCallback.onScanFailed();
+            Binder.clearCallingIdentity();
+            mExecutor.execute(() -> mCallback.onScanFailed());
         }
     }
 
     /**
-     * Result of a signal poll.
+     * Result of a signal poll requested using {@link #signalPoll(String)}.
      */
     public static class SignalPollResult {
-        // RSSI value in dBM.
-        public int currentRssi;
-        //Transmission bit rate in Mbps.
-        public int txBitrate;
-        // Association frequency in MHz.
-        public int associationFrequency;
-        //Last received packet bit rate in Mbps.
-        public int rxBitrate;
+        /** @hide */
+        public SignalPollResult(int currentRssiDbm, int txBitrateMbps, int rxBitrateMbps,
+                int associationFrequencyMHz) {
+            this.currentRssiDbm = currentRssiDbm;
+            this.txBitrateMbps = txBitrateMbps;
+            this.rxBitrateMbps = rxBitrateMbps;
+            this.associationFrequencyMHz = associationFrequencyMHz;
+        }
+
+        /**
+         * RSSI value in dBM.
+         */
+        public final int currentRssiDbm;
+
+        /**
+         * Transmission bit rate in Mbps.
+         */
+        public final int txBitrateMbps;
+
+        /**
+         * Last received packet bit rate in Mbps.
+         */
+        public final int rxBitrateMbps;
+
+        /**
+         * Association frequency in MHz.
+         */
+        public final int associationFrequencyMHz;
     }
 
     /**
-     * WiFi interface transimission counters.
+     * Transmission counters obtained using {@link #getTxPacketCounters(String)}.
      */
     public static class TxPacketCounters {
-        // Number of successfully transmitted packets.
-        public int txSucceeded;
-        // Number of tramsmission failures.
-        public int txFailed;
+        /** @hide */
+        public TxPacketCounters(int txPacketSucceeded, int txPacketFailed) {
+            this.txPacketSucceeded = txPacketSucceeded;
+            this.txPacketFailed = txPacketFailed;
+        }
+
+        /**
+         * Number of successfully transmitted packets.
+         */
+        public final int txPacketSucceeded;
+
+        /**
+         * Number of packet transmission failures.
+         */
+        public final int txPacketFailed;
     }
 
     /**
-     * Callbacks for SoftAp interface.
+     * Callbacks for SoftAp interface registered using
+     * {@link #registerApCallback(String, Executor, SoftApCallback)}.
      */
-    public interface SoftApListener {
+    public interface SoftApCallback {
         /**
-         * Invoked when there is some fatal failure in the lower layers.
+         * Invoked when there is a fatal failure and the SoftAp is shutdown.
          */
         void onFailure();
 
         /**
-         * Invoked when the associated stations changes.
+         * Invoked when there is a change in the associated station (STA).
+         * @param client Information about the client whose status has changed.
+         * @param isConnected Indication as to whether the client is connected (true), or
+         *                    disconnected (false).
          */
-        void onConnectedClientsChanged(NativeWifiClient client, boolean isConnected);
+        void onConnectedClientsChanged(@NonNull NativeWifiClient client, boolean isConnected);
 
         /**
-         * Invoked when the channel switch event happens.
+         * Invoked when a channel switch event happens - i.e. the SoftAp is moved to a different
+         * channel. Also called on initial registration.
+         * @param frequencyMhz The new frequency of the SoftAp. A value of 0 is invalid and is an
+         *                     indication that the SoftAp is not enabled.
+         * @param bandwidth The new bandwidth of the SoftAp.
          */
-        void onSoftApChannelSwitched(int frequency, int bandwidth);
+        void onSoftApChannelSwitched(int frequencyMhz, @WifiAnnotations.Bandwidth int bandwidth);
     }
 
     /**
      * Callback to notify the results of a
-     * {@link #sendMgmtFrame(String, byte[], SendMgmtFrameCallback, int) sendMgmtFrame()} call.
-     * Note: no callbacks will be triggered if the iface dies while sending a frame.
+     * {@link #sendMgmtFrame(String, byte[], int, Executor, SendMgmtFrameCallback)} call.
+     * Note: no callbacks will be triggered if the interface dies while sending a frame.
      */
     public interface SendMgmtFrameCallback {
         /**
@@ -211,6 +278,7 @@
         void onFailure(@SendMgmtFrameError int reason);
     }
 
+    /** @hide */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(prefix = {"SEND_MGMT_FRAME_ERROR_"},
             value = {SEND_MGMT_FRAME_ERROR_UNKNOWN,
@@ -224,43 +292,44 @@
 
     /**
      * Unknown error occurred during call to
-     * {@link #sendMgmtFrame(String, byte[], SendMgmtFrameCallback, int) sendMgmtFrame()}.
+     * {@link #sendMgmtFrame(String, byte[], int, Executor, SendMgmtFrameCallback)}.
      */
     public static final int SEND_MGMT_FRAME_ERROR_UNKNOWN = 1;
 
     /**
      * Specifying the MCS rate in
-     * {@link #sendMgmtFrame(String, byte[], SendMgmtFrameCallback, int) sendMgmtFrame()} is not
+     * {@link #sendMgmtFrame(String, byte[], int, Executor, SendMgmtFrameCallback)} is not
      * supported by this device.
      */
     public static final int SEND_MGMT_FRAME_ERROR_MCS_UNSUPPORTED = 2;
 
     /**
      * Driver reported that no ACK was received for the frame transmitted using
-     * {@link #sendMgmtFrame(String, byte[], SendMgmtFrameCallback, int) sendMgmtFrame()}.
+     * {@link #sendMgmtFrame(String, byte[], int, Executor, SendMgmtFrameCallback)}.
      */
     public static final int SEND_MGMT_FRAME_ERROR_NO_ACK = 3;
 
     /**
      * Error code for when the driver fails to report on the status of the frame sent by
-     * {@link #sendMgmtFrame(String, byte[], SendMgmtFrameCallback, int) sendMgmtFrame()}
+     * {@link #sendMgmtFrame(String, byte[], int, Executor, SendMgmtFrameCallback)}
      * after {@link #SEND_MGMT_FRAME_TIMEOUT_MS} milliseconds.
      */
     public static final int SEND_MGMT_FRAME_ERROR_TIMEOUT = 4;
 
     /**
      * An existing call to
-     * {@link #sendMgmtFrame(String, byte[], SendMgmtFrameCallback, int) sendMgmtFrame()}
+     * {@link #sendMgmtFrame(String, byte[], int, Executor, SendMgmtFrameCallback)}
      * is in progress. Another frame cannot be sent until the first call completes.
      */
     public static final int SEND_MGMT_FRAME_ERROR_ALREADY_STARTED = 5;
 
-
+    /** @hide */
     public WifiCondManager(Context context) {
-        mAlarmManager = (AlarmManager) context.getSystemService(AlarmManager.class);
+        mAlarmManager = context.getSystemService(AlarmManager.class);
         mEventHandler = new Handler(context.getMainLooper());
     }
 
+    /** @hide */
     @VisibleForTesting
     public WifiCondManager(Context context, IWificond wificond) {
         this(context);
@@ -268,22 +337,26 @@
     }
 
     private class PnoScanEventHandler extends IPnoScanEvent.Stub {
+        private Executor mExecutor;
         private ScanEventCallback mCallback;
 
-        PnoScanEventHandler(@NonNull ScanEventCallback callback) {
+        PnoScanEventHandler(@NonNull Executor executor, @NonNull ScanEventCallback callback) {
+            mExecutor = executor;
             mCallback = callback;
         }
 
         @Override
         public void OnPnoNetworkFound() {
             Log.d(TAG, "Pno scan result event");
-            mCallback.onScanResultReady();
+            Binder.clearCallingIdentity();
+            mExecutor.execute(() -> mCallback.onScanResultReady());
         }
 
         @Override
         public void OnPnoScanFailed() {
             Log.d(TAG, "Pno Scan failed event");
-            mCallback.onScanFailed();
+            Binder.clearCallingIdentity();
+            mExecutor.execute(() -> mCallback.onScanFailed());
         }
     }
 
@@ -291,9 +364,11 @@
      * Listener for AP Interface events.
      */
     private class ApInterfaceEventCallback extends IApInterfaceEventCallback.Stub {
-        private SoftApListener mSoftApListener;
+        private Executor mExecutor;
+        private SoftApCallback mSoftApListener;
 
-        ApInterfaceEventCallback(SoftApListener listener) {
+        ApInterfaceEventCallback(Executor executor, SoftApCallback listener) {
+            mExecutor = executor;
             mSoftApListener = listener;
         }
 
@@ -304,12 +379,36 @@
                         + client.macAddress + " isConnected: " + isConnected);
             }
 
-            mSoftApListener.onConnectedClientsChanged(client, isConnected);
+            Binder.clearCallingIdentity();
+            mExecutor.execute(() -> mSoftApListener.onConnectedClientsChanged(client, isConnected));
         }
 
         @Override
         public void onSoftApChannelSwitched(int frequency, int bandwidth) {
-            mSoftApListener.onSoftApChannelSwitched(frequency, bandwidth);
+            Binder.clearCallingIdentity();
+            mExecutor.execute(() -> mSoftApListener.onSoftApChannelSwitched(frequency,
+                    toFrameworkBandwidth(bandwidth)));
+        }
+
+        private @WifiAnnotations.Bandwidth int toFrameworkBandwidth(int bandwidth) {
+            switch(bandwidth) {
+                case IApInterfaceEventCallback.BANDWIDTH_INVALID:
+                    return SoftApInfo.CHANNEL_WIDTH_INVALID;
+                case IApInterfaceEventCallback.BANDWIDTH_20_NOHT:
+                    return SoftApInfo.CHANNEL_WIDTH_20MHZ_NOHT;
+                case IApInterfaceEventCallback.BANDWIDTH_20:
+                    return SoftApInfo.CHANNEL_WIDTH_20MHZ;
+                case IApInterfaceEventCallback.BANDWIDTH_40:
+                    return SoftApInfo.CHANNEL_WIDTH_40MHZ;
+                case IApInterfaceEventCallback.BANDWIDTH_80:
+                    return SoftApInfo.CHANNEL_WIDTH_80MHZ;
+                case IApInterfaceEventCallback.BANDWIDTH_80P80:
+                    return SoftApInfo.CHANNEL_WIDTH_80MHZ_PLUS_MHZ;
+                case IApInterfaceEventCallback.BANDWIDTH_160:
+                    return SoftApInfo.CHANNEL_WIDTH_160MHZ;
+                default:
+                    return SoftApInfo.CHANNEL_WIDTH_INVALID;
+            }
         }
     }
 
@@ -317,6 +416,7 @@
      * Callback triggered by wificond.
      */
     private class SendMgmtFrameEvent extends ISendMgmtFrameEvent.Stub {
+        private Executor mExecutor;
         private SendMgmtFrameCallback mCallback;
         private AlarmManager.OnAlarmListener mTimeoutCallback;
         /**
@@ -332,14 +432,16 @@
             r.run();
         }
 
-        SendMgmtFrameEvent(@NonNull SendMgmtFrameCallback callback) {
+        SendMgmtFrameEvent(@NonNull Executor executor, @NonNull SendMgmtFrameCallback callback) {
+            mExecutor = executor;
             mCallback = callback;
             // called in main thread
             mTimeoutCallback = () -> runIfFirstCall(() -> {
                 if (mVerboseLoggingEnabled) {
                     Log.e(TAG, "Timed out waiting for ACK");
                 }
-                mCallback.onFailure(SEND_MGMT_FRAME_ERROR_TIMEOUT);
+                Binder.clearCallingIdentity();
+                mExecutor.execute(() -> mCallback.onFailure(SEND_MGMT_FRAME_ERROR_TIMEOUT));
             });
             mWasCalled = false;
 
@@ -354,7 +456,8 @@
             // post to main thread
             mEventHandler.post(() -> runIfFirstCall(() -> {
                 mAlarmManager.cancel(mTimeoutCallback);
-                mCallback.onAck(elapsedTimeMs);
+                Binder.clearCallingIdentity();
+                mExecutor.execute(() -> mCallback.onAck(elapsedTimeMs));
             }));
         }
 
@@ -364,7 +467,8 @@
             // post to main thread
             mEventHandler.post(() -> runIfFirstCall(() -> {
                 mAlarmManager.cancel(mTimeoutCallback);
-                mCallback.onFailure(reason);
+                Binder.clearCallingIdentity();
+                mExecutor.execute(() -> mCallback.onFailure(reason));
             }));
         }
     }
@@ -372,8 +476,9 @@
     /**
      * Called by the binder subsystem upon remote object death.
      * Invoke all the register death handlers and clear state.
+     * @hide
      */
-    @Override
+    @VisibleForTesting
     public void binderDied() {
         mEventHandler.post(() -> {
             Log.e(TAG, "Wificond died!");
@@ -387,17 +492,22 @@
         });
     }
 
-    /** Enable or disable verbose logging of WificondControl.
-     *  @param enable True to enable verbose logging. False to disable verbose logging.
+    /**
+     * Enable or disable verbose logging of the WifiCondManager module.
+     * @param enable True to enable verbose logging. False to disable verbose logging.
      */
     public void enableVerboseLogging(boolean enable) {
         mVerboseLoggingEnabled = enable;
     }
 
     /**
-     * Initializes wificond & registers a death notification for wificond.
-     * This method clears any existing state in wificond daemon.
+     * Initializes WifiCondManager & registers a death notification for the WifiCondManager which
+     * acts as a proxy for the wificond daemon (i.e. the death listener will be called when and if
+     * the wificond daemon dies).
      *
+     * Note: This method clears any existing state in wificond daemon.
+     *
+     * @param deathEventHandler A {@link Runnable} to be called whenever the wificond daemon dies.
      * @return Returns true on success.
      */
     public boolean initialize(@NonNull Runnable deathEventHandler) {
@@ -428,7 +538,7 @@
             return false;
         }
         try {
-            mWificond.asBinder().linkToDeath(this, 0);
+            mWificond.asBinder().linkToDeath(() -> binderDied(), 0);
         } catch (RemoteException e) {
             Log.e(TAG, "Failed to register death notification for wificond");
             // The remote has already died.
@@ -438,16 +548,27 @@
     }
 
     /**
-    * Setup interface for client mode via wificond.
-    * @return true on success.
-    */
+     * Set up an interface for client (STA) mode.
+     *
+     * @param ifaceName Name of the interface to configure.
+     * @param executor The Executor on which to execute the callbacks.
+     * @param scanCallback A callback for framework initiated scans.
+     * @param pnoScanCallback A callback for PNO (offloaded) scans.
+     * @return true on success.
+     */
     public boolean setupInterfaceForClientMode(@NonNull String ifaceName,
+            @NonNull @CallbackExecutor Executor executor,
             @NonNull ScanEventCallback scanCallback, @NonNull ScanEventCallback pnoScanCallback) {
         Log.d(TAG, "Setting up interface for client mode");
         if (!retrieveWificondAndRegisterForDeath()) {
             return false;
         }
 
+        if (scanCallback == null || pnoScanCallback == null || executor == null) {
+            Log.e(TAG, "setupInterfaceForClientMode invoked with null callbacks");
+            return false;
+        }
+
         IClientInterface clientInterface = null;
         try {
             clientInterface = mWificond.createClientInterface(ifaceName);
@@ -472,10 +593,11 @@
             }
             mWificondScanners.put(ifaceName, wificondScanner);
             Binder.allowBlocking(wificondScanner.asBinder());
-            ScanEventHandler scanEventHandler = new ScanEventHandler(scanCallback);
+            ScanEventHandler scanEventHandler = new ScanEventHandler(executor, scanCallback);
             mScanEventHandlers.put(ifaceName,  scanEventHandler);
             wificondScanner.subscribeScanEvents(scanEventHandler);
-            PnoScanEventHandler pnoScanEventHandler = new PnoScanEventHandler(pnoScanCallback);
+            PnoScanEventHandler pnoScanEventHandler = new PnoScanEventHandler(executor,
+                    pnoScanCallback);
             mPnoScanEventHandlers.put(ifaceName,  pnoScanEventHandler);
             wificondScanner.subscribePnoScanEvents(pnoScanEventHandler);
         } catch (RemoteException e) {
@@ -486,8 +608,10 @@
     }
 
     /**
-     * Teardown a specific STA interface configured in wificond.
+     * Tear down a specific client (STA) interface, initially configured using
+     * {@link #setupInterfaceForClientMode(String, Executor, ScanEventCallback, ScanEventCallback)}.
      *
+     * @param ifaceName Name of the interface to tear down.
      * @return Returns true on success.
      */
     public boolean tearDownClientInterface(@NonNull String ifaceName) {
@@ -531,9 +655,11 @@
     }
 
     /**
-    * Setup interface for softAp mode via wificond.
-    * @return true on success.
-    */
+     * Set up interface as a Soft AP.
+     *
+     * @param ifaceName Name of the interface to configure.
+     * @return true on success.
+     */
     public boolean setupInterfaceForSoftApMode(@NonNull String ifaceName) {
         Log.d(TAG, "Setting up interface for soft ap mode");
         if (!retrieveWificondAndRegisterForDeath()) {
@@ -560,8 +686,10 @@
     }
 
     /**
-     * Teardown a specific AP interface configured in wificond.
+     * Tear down a Soft AP interface initially configured using
+     * {@link #setupInterfaceForSoftApMode(String)}.
      *
+     * @param ifaceName Name of the interface to tear down.
      * @return Returns true on success.
      */
     public boolean tearDownSoftApInterface(@NonNull String ifaceName) {
@@ -592,7 +720,8 @@
     }
 
     /**
-    * Teardown all interfaces configured in wificond.
+    * Tear down all interfaces, whether clients (STA) or Soft AP.
+     *
     * @return Returns true on success.
     */
     public boolean tearDownInterfaces() {
@@ -624,12 +753,13 @@
     }
 
     /**
-     * Request signal polling to wificond.
-     * @param ifaceName Name of the interface.
-     * Returns an SignalPollResult object.
-     * Returns null on failure.
+     * Request signal polling.
+     *
+     * @param ifaceName Name of the interface on which to poll.
+     * @return A {@link SignalPollResult} object containing interface statistics, or a null on
+     * error.
      */
-    public SignalPollResult signalPoll(@NonNull String ifaceName) {
+    @Nullable public SignalPollResult signalPoll(@NonNull String ifaceName) {
         IClientInterface iface = getClientInterface(ifaceName);
         if (iface == null) {
             Log.e(TAG, "No valid wificond client interface handler");
@@ -647,21 +777,16 @@
             Log.e(TAG, "Failed to do signal polling due to remote exception");
             return null;
         }
-        SignalPollResult pollResult = new SignalPollResult();
-        pollResult.currentRssi = resultArray[0];
-        pollResult.txBitrate = resultArray[1];
-        pollResult.associationFrequency = resultArray[2];
-        pollResult.rxBitrate = resultArray[3];
-        return pollResult;
+        return new SignalPollResult(resultArray[0], resultArray[1], resultArray[3], resultArray[2]);
     }
 
     /**
-     * Fetch TX packet counters on current connection from wificond.
+     * Get current transmit (Tx) packet counters of the specified interface.
+     *
      * @param ifaceName Name of the interface.
-     * Returns an TxPacketCounters object.
-     * Returns null on failure.
+     * @return {@link TxPacketCounters} of the current interface or null on error.
      */
-    public TxPacketCounters getTxPacketCounters(@NonNull String ifaceName) {
+    @Nullable public TxPacketCounters getTxPacketCounters(@NonNull String ifaceName) {
         IClientInterface iface = getClientInterface(ifaceName);
         if (iface == null) {
             Log.e(TAG, "No valid wificond client interface handler");
@@ -679,10 +804,7 @@
             Log.e(TAG, "Failed to do signal polling due to remote exception");
             return null;
         }
-        TxPacketCounters counters = new TxPacketCounters();
-        counters.txSucceeded = resultArray[0];
-        counters.txFailed = resultArray[1];
-        return counters;
+        return new TxPacketCounters(resultArray[0], resultArray[1]);
     }
 
     /** Helper function to look up the scanner impl handle using name */
@@ -691,10 +813,16 @@
     }
 
     /**
-    * Fetch the latest scan result from kernel via wificond.
-    * @param ifaceName Name of the interface.
-    * @return Returns an array of native scan results or an empty array on failure.
-    */
+     * Fetch the latest scan results of the indicated type for the specified interface. Note that
+     * this method fetches the latest results - it does not initiate a scan. Initiating a scan can
+     * be done using {@link #startScan(String, int, Set, List)} or
+     * {@link #startPnoScan(String, PnoSettings, Executor, PnoScanRequestCallback)}.
+     *
+     * @param ifaceName Name of the interface.
+     * @param scanType The type of scan result to be returned, can be
+     * {@link #SCAN_TYPE_SINGLE_SCAN} or {@link #SCAN_TYPE_PNO_SCAN}.
+     * @return Returns an array of {@link NativeScanResult} or an empty array on failure.
+     */
     @NonNull public List<NativeScanResult> getScanResults(@NonNull String ifaceName,
             @ScanResultType int scanType) {
         IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName);
@@ -739,15 +867,23 @@
     }
 
     /**
-     * Start a scan using wificond for the given parameters.
-     * @param ifaceName Name of the interface.
-     * @param scanType Type of scan to perform.
+     * Start a scan using the specified parameters. A scan is an asynchronous operation. The
+     * result of the operation is returned in the {@link ScanEventCallback} registered when
+     * setting up an interface using
+     * {@link #setupInterfaceForClientMode(String, Executor, ScanEventCallback, ScanEventCallback)}.
+     * The latest scans can be obtained using {@link #getScanResults(String, int)} and using a
+     * {@link #SCAN_TYPE_SINGLE_SCAN} for the {@code scanType}.
+     *
+     * @param ifaceName Name of the interface on which to initiate the scan.
+     * @param scanType Type of scan to perform, can be any of
+     * {@link WifiScanner#SCAN_TYPE_HIGH_ACCURACY}, {@link WifiScanner#SCAN_TYPE_LOW_POWER}, or
+     * {@link WifiScanner#SCAN_TYPE_LOW_LATENCY}.
      * @param freqs list of frequencies to scan for, if null scan all supported channels.
      * @param hiddenNetworkSSIDs List of hidden networks to be scanned for.
      * @return Returns true on success.
      */
-    public boolean scan(@NonNull String ifaceName, @WifiAnnotations.ScanType int scanType,
-            Set<Integer> freqs, List<byte[]> hiddenNetworkSSIDs) {
+    public boolean startScan(@NonNull String ifaceName, @WifiAnnotations.ScanType int scanType,
+            @Nullable Set<Integer> freqs, @Nullable List<byte[]> hiddenNetworkSSIDs) {
         IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName);
         if (scannerImpl == null) {
             Log.e(TAG, "No valid wificond scanner interface handler");
@@ -792,25 +928,40 @@
     }
 
     /**
-     * Start PNO scan.
-     * @param ifaceName Name of the interface.
-     * @param pnoSettings Pno scan configuration.
+     * Request a PNO (Preferred Network Offload). The offload request and the scans are asynchronous
+     * operations. The result of the request are returned in the {@code callback} parameter which
+     * is an {@link PnoScanRequestCallback}. The scan results are are return in the
+     * {@link ScanEventCallback} which is registered when setting up an interface using
+     * {@link #setupInterfaceForClientMode(String, Executor, ScanEventCallback, ScanEventCallback)}.
+     * The latest PNO scans can be obtained using {@link #getScanResults(String, int)} with the
+     * {@code scanType} set to {@link #SCAN_TYPE_PNO_SCAN}.
+     *
+     * @param ifaceName Name of the interface on which to request a PNO.
+     * @param pnoSettings PNO scan configuration.
+     * @param executor The Executor on which to execute the callback.
+     * @param callback Callback for the results of the offload request.
      * @return true on success.
      */
-    public boolean startPnoScan(@NonNull String ifaceName, PnoSettings pnoSettings,
-            PnoScanRequestCallback callback) {
+    public boolean startPnoScan(@NonNull String ifaceName, @NonNull PnoSettings pnoSettings,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull PnoScanRequestCallback callback) {
         IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName);
         if (scannerImpl == null) {
             Log.e(TAG, "No valid wificond scanner interface handler");
             return false;
         }
 
+        if (callback == null || executor == null) {
+            Log.e(TAG, "startPnoScan called with a null callback");
+            return false;
+        }
+
         try {
             boolean success = scannerImpl.startPnoScan(pnoSettings);
             if (success) {
-                callback.onPnoRequestSucceeded();
+                executor.execute(callback::onPnoRequestSucceeded);
             } else {
-                callback.onPnoRequestFailed();
+                executor.execute(callback::onPnoRequestFailed);
             }
             return success;
         } catch (RemoteException e1) {
@@ -820,8 +971,10 @@
     }
 
     /**
-     * Stop PNO scan.
-     * @param ifaceName Name of the interface.
+     * Stop PNO scan configured with
+     * {@link #startPnoScan(String, PnoSettings, Executor, PnoScanRequestCallback)}.
+     *
+     * @param ifaceName Name of the interface on which the PNO scan was configured.
      * @return true on success.
      */
     public boolean stopPnoScan(@NonNull String ifaceName) {
@@ -839,8 +992,9 @@
     }
 
     /**
-     * Abort ongoing single scan.
-     * @param ifaceName Name of the interface.
+     * Abort ongoing single scan started with {@link #startScan(String, int, Set, List)}.
+     *
+     * @param ifaceName Name of the interface on which the scan was started.
      */
     public void abortScan(@NonNull String ifaceName) {
         IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName);
@@ -856,7 +1010,7 @@
     }
 
     /**
-     * Query the list of valid frequencies for the provided band.
+     * Query the list of valid frequencies (in MHz) for the provided band.
      * The result depends on the on the country code that has been set.
      *
      * @param band as specified by one of the WifiScanner.WIFI_BAND_* constants.
@@ -865,31 +1019,39 @@
      * WifiScanner.WIFI_BAND_5_GHZ
      * WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY
      * WifiScanner.WIFI_BAND_6_GHZ
-     * @return frequencies vector of valid frequencies (MHz), or null for error.
+     * @return frequencies vector of valid frequencies (MHz), or an empty array for error.
      * @throws IllegalArgumentException if band is not recognized.
      */
-    public int [] getChannelsForBand(@WifiAnnotations.WifiBandBasic int band) {
+    public @NonNull int[] getChannelsMhzForBand(@WifiAnnotations.WifiBandBasic int band) {
         if (mWificond == null) {
             Log.e(TAG, "No valid wificond scanner interface handler");
-            return null;
+            return new int[0];
         }
+        int[] result = null;
         try {
             switch (band) {
                 case WifiScanner.WIFI_BAND_24_GHZ:
-                    return mWificond.getAvailable2gChannels();
+                    result = mWificond.getAvailable2gChannels();
+                    break;
                 case WifiScanner.WIFI_BAND_5_GHZ:
-                    return mWificond.getAvailable5gNonDFSChannels();
+                    result = mWificond.getAvailable5gNonDFSChannels();
+                    break;
                 case WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY:
-                    return mWificond.getAvailableDFSChannels();
+                    result = mWificond.getAvailableDFSChannels();
+                    break;
                 case WifiScanner.WIFI_BAND_6_GHZ:
-                    return mWificond.getAvailable6gChannels();
+                    result = mWificond.getAvailable6gChannels();
+                    break;
                 default:
                     throw new IllegalArgumentException("unsupported band " + band);
             }
         } catch (RemoteException e1) {
             Log.e(TAG, "Failed to request getChannelsForBand due to remote exception");
         }
-        return null;
+        if (result == null) {
+            result = new int[0];
+        }
+        return result;
     }
 
     /** Helper function to look up the interface handle using name */
@@ -898,22 +1060,33 @@
     }
 
     /**
-     * Register the provided listener for SoftAp events.
+     * Register the provided callback handler for SoftAp events. Note that the Soft AP itself is
+     * configured using {@link #setupInterfaceForSoftApMode(String)}.
      *
-     * @param ifaceName Name of the interface.
-     * @param listener Callback for AP events.
+     * @param ifaceName Name of the interface on which to register the callback.
+     * @param executor The Executor on which to execute the callbacks.
+     * @param callback Callback for AP events.
      * @return true on success, false otherwise.
      */
-    public boolean registerApListener(@NonNull String ifaceName, SoftApListener listener) {
+    public boolean registerApCallback(@NonNull String ifaceName,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull SoftApCallback callback) {
         IApInterface iface = getApInterface(ifaceName);
         if (iface == null) {
             Log.e(TAG, "No valid ap interface handler");
             return false;
         }
+
+        if (callback == null || executor == null) {
+            Log.e(TAG, "registerApCallback called with a null callback");
+            return false;
+        }
+
         try {
-            IApInterfaceEventCallback  callback = new ApInterfaceEventCallback(listener);
-            mApInterfaceListeners.put(ifaceName, callback);
-            boolean success = iface.registerCallback(callback);
+            IApInterfaceEventCallback wificondCallback = new ApInterfaceEventCallback(executor,
+                    callback);
+            mApInterfaceListeners.put(ifaceName, wificondCallback);
+            boolean success = iface.registerCallback(wificondCallback);
             if (!success) {
                 Log.e(TAG, "Failed to register ap callback.");
                 return false;
@@ -926,19 +1099,28 @@
     }
 
     /**
-     * See {@link #sendMgmtFrame(String, byte[], SendMgmtFrameCallback, int)}
+     * Send a management frame on the specified interface at the specified rate. Useful for probing
+     * the link with arbitrary frames.
+     *
+     * @param ifaceName The interface on which to send the frame.
+     * @param frame The raw byte array of the management frame to tramit.
+     * @param mcs The MCS (modulation and coding scheme), i.e. rate, at which to transmit the
+     *            frame. Specified per IEEE 802.11.
+     * @param executor The Executor on which to execute the callbacks.
+     * @param callback A {@link SendMgmtFrameCallback} callback for results of the operation.
      */
-    public void sendMgmtFrame(@NonNull String ifaceName, @NonNull byte[] frame,
-            @NonNull SendMgmtFrameCallback callback, int mcs) {
+    public void sendMgmtFrame(@NonNull String ifaceName, @NonNull byte[] frame, int mcs,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull SendMgmtFrameCallback callback) {
 
-        if (callback == null) {
+        if (callback == null || executor == null) {
             Log.e(TAG, "callback cannot be null!");
             return;
         }
 
         if (frame == null) {
             Log.e(TAG, "frame cannot be null!");
-            callback.onFailure(SEND_MGMT_FRAME_ERROR_UNKNOWN);
+            executor.execute(() -> callback.onFailure(SEND_MGMT_FRAME_ERROR_UNKNOWN));
             return;
         }
 
@@ -946,17 +1128,17 @@
         IClientInterface clientInterface = getClientInterface(ifaceName);
         if (clientInterface == null) {
             Log.e(TAG, "No valid wificond client interface handler");
-            callback.onFailure(SEND_MGMT_FRAME_ERROR_UNKNOWN);
+            executor.execute(() -> callback.onFailure(SEND_MGMT_FRAME_ERROR_UNKNOWN));
             return;
         }
 
         if (!mSendMgmtFrameInProgress.compareAndSet(false, true)) {
             Log.e(TAG, "An existing management frame transmission is in progress!");
-            callback.onFailure(SEND_MGMT_FRAME_ERROR_ALREADY_STARTED);
+            executor.execute(() -> callback.onFailure(SEND_MGMT_FRAME_ERROR_ALREADY_STARTED));
             return;
         }
 
-        SendMgmtFrameEvent sendMgmtFrameEvent = new SendMgmtFrameEvent(callback);
+        SendMgmtFrameEvent sendMgmtFrameEvent = new SendMgmtFrameEvent(executor, callback);
         try {
             clientInterface.SendMgmtFrame(frame, sendMgmtFrameEvent, mcs);
         } catch (RemoteException e) {
diff --git a/wifi/tests/src/android/net/wifi/wificond/PnoSettingsTest.java b/wifi/tests/src/android/net/wifi/wificond/PnoSettingsTest.java
index 775acc7..9439c79 100644
--- a/wifi/tests/src/android/net/wifi/wificond/PnoSettingsTest.java
+++ b/wifi/tests/src/android/net/wifi/wificond/PnoSettingsTest.java
@@ -30,7 +30,7 @@
 import java.util.HashMap;
 
 /**
- * Unit tests for {@link android.net.wifi.wificond.PnoSettingsResult}.
+ * Unit tests for {@link android.net.wifi.wificond.PnoSettings}.
  */
 @SmallTest
 public class PnoSettingsTest {
@@ -52,14 +52,14 @@
     @Before
     public void setUp() {
         mPnoNetwork1 = new PnoNetwork();
-        mPnoNetwork1.ssid = TEST_SSID_1;
-        mPnoNetwork1.isHidden = true;
-        mPnoNetwork1.frequencies = TEST_FREQUENCIES_1;
+        mPnoNetwork1.setSsid(TEST_SSID_1);
+        mPnoNetwork1.setHidden(true);
+        mPnoNetwork1.setFrequenciesMhz(TEST_FREQUENCIES_1);
 
         mPnoNetwork2 = new PnoNetwork();
-        mPnoNetwork2.ssid = TEST_SSID_2;
-        mPnoNetwork2.isHidden = false;
-        mPnoNetwork2.frequencies = TEST_FREQUENCIES_2;
+        mPnoNetwork2.setSsid(TEST_SSID_2);
+        mPnoNetwork2.setHidden(false);
+        mPnoNetwork2.setFrequenciesMhz(TEST_FREQUENCIES_2);
     }
 
     /**
@@ -69,10 +69,10 @@
     @Test
     public void canSerializeAndDeserialize() {
         PnoSettings pnoSettings = new PnoSettings();
-        pnoSettings.intervalMs = TEST_INTERVAL_MS;
-        pnoSettings.min2gRssi = TEST_MIN_2G_RSSI;
-        pnoSettings.min5gRssi = TEST_MIN_5G_RSSI;
-        pnoSettings.pnoNetworks = new ArrayList<>(Arrays.asList(mPnoNetwork1, mPnoNetwork2));
+        pnoSettings.setIntervalMillis(TEST_INTERVAL_MS);
+        pnoSettings.setMin2gRssiDbm(TEST_MIN_2G_RSSI);
+        pnoSettings.setMin5gRssiDbm(TEST_MIN_5G_RSSI);
+        pnoSettings.setPnoNetworks(new ArrayList<>(Arrays.asList(mPnoNetwork1, mPnoNetwork2)));
 
         Parcel parcel = Parcel.obtain();
         pnoSettings.writeToParcel(parcel, 0);
@@ -90,16 +90,16 @@
     @Test
     public void testAsHashMapKey() {
         PnoSettings pnoSettings1 = new PnoSettings();
-        pnoSettings1.intervalMs = TEST_INTERVAL_MS;
-        pnoSettings1.min2gRssi = TEST_MIN_2G_RSSI;
-        pnoSettings1.min5gRssi = TEST_MIN_5G_RSSI;
-        pnoSettings1.pnoNetworks = new ArrayList<>(Arrays.asList(mPnoNetwork1, mPnoNetwork2));
+        pnoSettings1.setIntervalMillis(TEST_INTERVAL_MS);
+        pnoSettings1.setMin2gRssiDbm(TEST_MIN_2G_RSSI);
+        pnoSettings1.setMin5gRssiDbm(TEST_MIN_5G_RSSI);
+        pnoSettings1.setPnoNetworks(new ArrayList<>(Arrays.asList(mPnoNetwork1, mPnoNetwork2)));
 
         PnoSettings pnoSettings2 = new PnoSettings();
-        pnoSettings2.intervalMs = TEST_INTERVAL_MS;
-        pnoSettings2.min2gRssi = TEST_MIN_2G_RSSI;
-        pnoSettings2.min5gRssi = TEST_MIN_5G_RSSI;
-        pnoSettings2.pnoNetworks = new ArrayList<>(Arrays.asList(mPnoNetwork1, mPnoNetwork2));
+        pnoSettings2.setIntervalMillis(TEST_INTERVAL_MS);
+        pnoSettings2.setMin2gRssiDbm(TEST_MIN_2G_RSSI);
+        pnoSettings2.setMin5gRssiDbm(TEST_MIN_5G_RSSI);
+        pnoSettings2.setPnoNetworks(new ArrayList<>(Arrays.asList(mPnoNetwork1, mPnoNetwork2)));
 
         assertEquals(pnoSettings1, pnoSettings2);
         assertEquals(pnoSettings1.hashCode(), pnoSettings2.hashCode());
diff --git a/wifi/tests/src/android/net/wifi/WifiCondManagerTest.java b/wifi/tests/src/android/net/wifi/wificond/WifiCondManagerTest.java
similarity index 89%
rename from wifi/tests/src/android/net/wifi/WifiCondManagerTest.java
rename to wifi/tests/src/android/net/wifi/wificond/WifiCondManagerTest.java
index 48a9afa..68e5336 100644
--- a/wifi/tests/src/android/net/wifi/WifiCondManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/wificond/WifiCondManagerTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.net.wifi;
+package android.net.wifi.wificond;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -38,13 +38,18 @@
 import android.app.AlarmManager;
 import android.app.test.TestAlarmManager;
 import android.content.Context;
+import android.net.wifi.IApInterface;
+import android.net.wifi.IApInterfaceEventCallback;
+import android.net.wifi.IClientInterface;
+import android.net.wifi.IPnoScanEvent;
+import android.net.wifi.IScanEvent;
+import android.net.wifi.ISendMgmtFrameEvent;
+import android.net.wifi.IWifiScannerImpl;
+import android.net.wifi.IWificond;
+import android.net.wifi.SoftApInfo;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiScanner;
 import android.net.wifi.util.HexEncoding;
-import android.net.wifi.wificond.ChannelSettings;
-import android.net.wifi.wificond.HiddenNetwork;
-import android.net.wifi.wificond.NativeWifiClient;
-import android.net.wifi.wificond.PnoNetwork;
-import android.net.wifi.wificond.PnoSettings;
-import android.net.wifi.wificond.SingleScanSettings;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -67,7 +72,6 @@
 import java.nio.charset.CharsetEncoder;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
@@ -88,7 +92,7 @@
     @Mock
     private IApInterface mApInterface;
     @Mock
-    private WifiCondManager.SoftApListener mSoftApListener;
+    private WifiCondManager.SoftApCallback mSoftApListener;
     @Mock
     private WifiCondManager.SendMgmtFrameCallback mSendMgmtFrameCallback;
     @Mock
@@ -122,6 +126,7 @@
     private static final String TEST_QUOTED_SSID_2 = "\"testSsid2\"";
     private static final int[] TEST_FREQUENCIES_1 = {};
     private static final int[] TEST_FREQUENCIES_2 = {2500, 5124};
+    private static final byte[] TEST_RAW_MAC_BYTES = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05};
 
     private static final List<byte[]> SCAN_HIDDEN_NETWORK_SSID_LIST =
             new ArrayList<byte[]>() {{
@@ -131,22 +136,23 @@
                         LocalNativeUtil.decodeSsid(TEST_QUOTED_SSID_2)));
             }};
 
-    private static final PnoSettings TEST_PNO_SETTINGS =
-            new PnoSettings() {{
-                intervalMs = 6000;
-                pnoNetworks = new ArrayList<>();
-                PnoNetwork network = new PnoNetwork();
-                network.ssid = LocalNativeUtil.byteArrayFromArrayList(
-                        LocalNativeUtil.decodeSsid(TEST_QUOTED_SSID_1));
-                network.isHidden = true;
-                network.frequencies = TEST_FREQUENCIES_1;
-                pnoNetworks.add(network);
-                network.ssid = LocalNativeUtil.byteArrayFromArrayList(
-                        LocalNativeUtil.decodeSsid(TEST_QUOTED_SSID_2));
-                network.isHidden = false;
-                network.frequencies = TEST_FREQUENCIES_2;
-                pnoNetworks.add(network);
-            }};
+    private static final PnoSettings TEST_PNO_SETTINGS = new PnoSettings();
+    static {
+        TEST_PNO_SETTINGS.setIntervalMillis(6000);
+        List<PnoNetwork> initPnoNetworks = new ArrayList<>();
+        PnoNetwork network = new PnoNetwork();
+        network.setSsid(LocalNativeUtil.byteArrayFromArrayList(
+                LocalNativeUtil.decodeSsid(TEST_QUOTED_SSID_1)));
+        network.setHidden(true);
+        network.setFrequenciesMhz(TEST_FREQUENCIES_1);
+        initPnoNetworks.add(network);
+        network.setSsid(LocalNativeUtil.byteArrayFromArrayList(
+                LocalNativeUtil.decodeSsid(TEST_QUOTED_SSID_2)));
+        network.setHidden(false);
+        network.setFrequenciesMhz(TEST_FREQUENCIES_2);
+        initPnoNetworks.add(network);
+        TEST_PNO_SETTINGS.setPnoNetworks(initPnoNetworks);
+    }
 
     private static final int TEST_MCS_RATE = 5;
     private static final int TEST_SEND_MGMT_FRAME_ELAPSED_TIME_MS = 100;
@@ -180,8 +186,9 @@
         when(mClientInterface.getWifiScannerImpl()).thenReturn(mWifiScannerImpl);
         when(mClientInterface.getInterfaceName()).thenReturn(TEST_INTERFACE_NAME);
         mWificondControl = new WifiCondManager(mContext, mWificond);
-        assertEquals(true, mWificondControl.setupInterfaceForClientMode(TEST_INTERFACE_NAME,
-                mNormalScanCallback, mPnoScanCallback));
+        assertEquals(true,
+                mWificondControl.setupInterfaceForClientMode(TEST_INTERFACE_NAME, Runnable::run,
+                        mNormalScanCallback, mPnoScanCallback));
     }
 
     /**
@@ -264,7 +271,7 @@
         assertNull(mWificondControl.signalPoll(TEST_INTERFACE_NAME));
         verify(mClientInterface, never()).signalPoll();
 
-        assertFalse(mWificondControl.scan(
+        assertFalse(mWificondControl.startScan(
                 TEST_INTERFACE_NAME, WifiScanner.SCAN_TYPE_LOW_LATENCY,
                 SCAN_FREQ_SET, SCAN_HIDDEN_NETWORK_SSID_LIST));
         verify(mWifiScannerImpl, never()).scan(any());
@@ -348,8 +355,8 @@
     public void testTeardownSoftApInterfaceClearsHandles() throws Exception {
         testTeardownSoftApInterface();
 
-        assertFalse(mWificondControl.registerApListener(
-                TEST_INTERFACE_NAME, mSoftApListener));
+        assertFalse(mWificondControl.registerApCallback(
+                TEST_INTERFACE_NAME, Runnable::run, mSoftApListener));
         verify(mApInterface, never()).registerCallback(any());
     }
 
@@ -417,8 +424,8 @@
     public void testSignalPoll() throws Exception {
         when(mWificond.createClientInterface(TEST_INTERFACE_NAME)).thenReturn(mClientInterface);
 
-        mWificondControl.setupInterfaceForClientMode(TEST_INTERFACE_NAME, mNormalScanCallback,
-                mPnoScanCallback);
+        mWificondControl.setupInterfaceForClientMode(TEST_INTERFACE_NAME, Runnable::run,
+                mNormalScanCallback, mPnoScanCallback);
         mWificondControl.signalPoll(TEST_INTERFACE_NAME);
         verify(mClientInterface).signalPoll();
     }
@@ -432,7 +439,7 @@
 
         // Configure client interface.
         assertEquals(true, mWificondControl.setupInterfaceForClientMode(TEST_INTERFACE_NAME,
-                mNormalScanCallback, mPnoScanCallback));
+                Runnable::run, mNormalScanCallback, mPnoScanCallback));
 
         // Tear down interfaces.
         assertTrue(mWificondControl.tearDownInterfaces());
@@ -448,8 +455,8 @@
     public void testGetTxPacketCounters() throws Exception {
         when(mWificond.createClientInterface(TEST_INTERFACE_NAME)).thenReturn(mClientInterface);
 
-        mWificondControl.setupInterfaceForClientMode(TEST_INTERFACE_NAME, mNormalScanCallback,
-                mPnoScanCallback);
+        mWificondControl.setupInterfaceForClientMode(TEST_INTERFACE_NAME, Runnable::run,
+                mNormalScanCallback, mPnoScanCallback);
         mWificondControl.getTxPacketCounters(TEST_INTERFACE_NAME);
         verify(mClientInterface).getPacketCounters();
     }
@@ -464,7 +471,7 @@
 
         // Configure client interface.
         assertEquals(true, mWificondControl.setupInterfaceForClientMode(TEST_INTERFACE_NAME,
-                mNormalScanCallback, mPnoScanCallback));
+                Runnable::run, mNormalScanCallback, mPnoScanCallback));
 
         // Tear down interfaces.
         assertTrue(mWificondControl.tearDownInterfaces());
@@ -483,7 +490,7 @@
 
         // Configure client interface.
         assertEquals(true, mWificondControl.setupInterfaceForClientMode(TEST_INTERFACE_NAME,
-                mNormalScanCallback, mPnoScanCallback));
+                Runnable::run, mNormalScanCallback, mPnoScanCallback));
 
         // Tear down interfaces.
         assertTrue(mWificondControl.tearDownInterfaces());
@@ -500,7 +507,7 @@
     @Test
     public void testScan() throws Exception {
         when(mWifiScannerImpl.scan(any(SingleScanSettings.class))).thenReturn(true);
-        assertTrue(mWificondControl.scan(
+        assertTrue(mWificondControl.startScan(
                 TEST_INTERFACE_NAME, WifiScanner.SCAN_TYPE_LOW_POWER,
                 SCAN_FREQ_SET, SCAN_HIDDEN_NETWORK_SSID_LIST));
         verify(mWifiScannerImpl).scan(argThat(new ScanMatcher(
@@ -520,7 +527,7 @@
         assertEquals(hiddenSsidWithDup.get(0),
                 hiddenSsidWithDup.get(hiddenSsidWithDup.size() - 1));
         // Pass the List with duplicate elements into scan()
-        assertTrue(mWificondControl.scan(
+        assertTrue(mWificondControl.startScan(
                 TEST_INTERFACE_NAME, WifiScanner.SCAN_TYPE_LOW_POWER,
                 SCAN_FREQ_SET, hiddenSsidWithDup));
         // But the argument passed down should have the duplicate removed.
@@ -535,7 +542,7 @@
     @Test
     public void testScanNullParameters() throws Exception {
         when(mWifiScannerImpl.scan(any(SingleScanSettings.class))).thenReturn(true);
-        assertTrue(mWificondControl.scan(
+        assertTrue(mWificondControl.startScan(
                 TEST_INTERFACE_NAME, WifiScanner.SCAN_TYPE_HIGH_ACCURACY, null, null));
         verify(mWifiScannerImpl).scan(argThat(new ScanMatcher(
                 IWifiScannerImpl.SCAN_TYPE_HIGH_ACCURACY, null, null)));
@@ -547,7 +554,7 @@
     @Test
     public void testScanFailure() throws Exception {
         when(mWifiScannerImpl.scan(any(SingleScanSettings.class))).thenReturn(false);
-        assertFalse(mWificondControl.scan(
+        assertFalse(mWificondControl.startScan(
                 TEST_INTERFACE_NAME, WifiScanner.SCAN_TYPE_LOW_LATENCY,
                 SCAN_FREQ_SET, SCAN_HIDDEN_NETWORK_SSID_LIST));
         verify(mWifiScannerImpl).scan(any(SingleScanSettings.class));
@@ -558,7 +565,7 @@
      */
     @Test
     public void testScanFailureDueToInvalidType() throws Exception {
-        assertFalse(mWificondControl.scan(
+        assertFalse(mWificondControl.startScan(
                 TEST_INTERFACE_NAME, 100,
                 SCAN_FREQ_SET, SCAN_HIDDEN_NETWORK_SSID_LIST));
         verify(mWifiScannerImpl, never()).scan(any(SingleScanSettings.class));
@@ -570,9 +577,10 @@
     @Test
     public void testStartPnoScan() throws Exception {
         when(mWifiScannerImpl.startPnoScan(any(PnoSettings.class))).thenReturn(true);
-        assertTrue(mWificondControl.startPnoScan(TEST_INTERFACE_NAME, TEST_PNO_SETTINGS,
-                mPnoScanRequestCallback));
-        verify(mWifiScannerImpl).startPnoScan(argThat(new PnoScanMatcher(TEST_PNO_SETTINGS)));
+        assertTrue(
+                mWificondControl.startPnoScan(TEST_INTERFACE_NAME, TEST_PNO_SETTINGS, Runnable::run,
+                        mPnoScanRequestCallback));
+        verify(mWifiScannerImpl).startPnoScan(eq(TEST_PNO_SETTINGS));
         verify(mPnoScanRequestCallback).onPnoRequestSucceeded();
     }
 
@@ -665,8 +673,9 @@
     public void testStartPnoScanForMetrics() throws Exception {
         when(mWifiScannerImpl.startPnoScan(any(PnoSettings.class))).thenReturn(false);
 
-        assertFalse(mWificondControl.startPnoScan(TEST_INTERFACE_NAME, TEST_PNO_SETTINGS,
-                mPnoScanRequestCallback));
+        assertFalse(
+                mWificondControl.startPnoScan(TEST_INTERFACE_NAME, TEST_PNO_SETTINGS, Runnable::run,
+                        mPnoScanRequestCallback));
         verify(mPnoScanRequestCallback).onPnoRequestFailed();
     }
 
@@ -695,11 +704,11 @@
         final ArgumentCaptor<IApInterfaceEventCallback> apInterfaceCallbackCaptor =
                 ArgumentCaptor.forClass(IApInterfaceEventCallback.class);
 
-        assertTrue(mWificondControl.registerApListener(
-                TEST_INTERFACE_NAME, mSoftApListener));
+        assertTrue(mWificondControl.registerApCallback(
+                TEST_INTERFACE_NAME, Runnable::run, mSoftApListener));
         verify(mApInterface).registerCallback(apInterfaceCallbackCaptor.capture());
 
-        final NativeWifiClient testClient = new NativeWifiClient();
+        final NativeWifiClient testClient = new NativeWifiClient(TEST_RAW_MAC_BYTES);
         apInterfaceCallbackCaptor.getValue().onConnectedClientsChanged(testClient, true);
         verify(mSoftApListener).onConnectedClientsChanged(eq(testClient), eq(true));
 
@@ -707,7 +716,8 @@
         int channelBandwidth = IApInterfaceEventCallback.BANDWIDTH_20;
         apInterfaceCallbackCaptor.getValue().onSoftApChannelSwitched(channelFrequency,
                 channelBandwidth);
-        verify(mSoftApListener).onSoftApChannelSwitched(eq(channelFrequency), eq(channelBandwidth));
+        verify(mSoftApListener).onSoftApChannelSwitched(eq(channelFrequency),
+                eq(SoftApInfo.CHANNEL_WIDTH_20MHZ));
     }
 
     /**
@@ -739,7 +749,7 @@
         verify(deathHandler).run();
 
         // The handles should be cleared after death.
-        assertNull(mWificondControl.getChannelsForBand(WifiScanner.WIFI_BAND_5_GHZ));
+        assertEquals(0, mWificondControl.getChannelsMhzForBand(WifiScanner.WIFI_BAND_5_GHZ).length);
         verify(mWificond, never()).getAvailable5gNonDFSChannels();
     }
 
@@ -748,7 +758,8 @@
      */
     @Test
     public void testSendMgmtFrameNullCallback() throws Exception {
-        mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, TEST_PROBE_FRAME, null, TEST_MCS_RATE);
+        mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, TEST_PROBE_FRAME, TEST_MCS_RATE,
+                Runnable::run, null);
 
         verify(mClientInterface, never()).SendMgmtFrame(any(), any(), anyInt());
     }
@@ -758,8 +769,8 @@
      */
     @Test
     public void testSendMgmtFrameNullFrame() throws Exception {
-        mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, null,
-                mSendMgmtFrameCallback, TEST_MCS_RATE);
+        mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, null, TEST_MCS_RATE, Runnable::run,
+                mSendMgmtFrameCallback);
 
         verify(mClientInterface, never()).SendMgmtFrame(any(), any(), anyInt());
         verify(mSendMgmtFrameCallback).onFailure(anyInt());
@@ -770,8 +781,8 @@
      */
     @Test
     public void testSendMgmtFrameInvalidInterfaceName() throws Exception {
-        mWificondControl.sendMgmtFrame(TEST_INVALID_INTERFACE_NAME, TEST_PROBE_FRAME,
-                mSendMgmtFrameCallback, TEST_MCS_RATE);
+        mWificondControl.sendMgmtFrame(TEST_INVALID_INTERFACE_NAME, TEST_PROBE_FRAME, TEST_MCS_RATE,
+                Runnable::run, mSendMgmtFrameCallback);
 
         verify(mClientInterface, never()).SendMgmtFrame(any(), any(), anyInt());
         verify(mSendMgmtFrameCallback).onFailure(anyInt());
@@ -787,13 +798,15 @@
         WifiCondManager.SendMgmtFrameCallback cb2 = mock(
                 WifiCondManager.SendMgmtFrameCallback.class);
 
-        mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, TEST_PROBE_FRAME, cb1, TEST_MCS_RATE);
+        mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, TEST_PROBE_FRAME, TEST_MCS_RATE,
+                Runnable::run, cb1);
         verify(cb1, never()).onFailure(anyInt());
         verify(mClientInterface, times(1))
                 .SendMgmtFrame(AdditionalMatchers.aryEq(TEST_PROBE_FRAME),
                         any(), eq(TEST_MCS_RATE));
 
-        mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, TEST_PROBE_FRAME, cb2, TEST_MCS_RATE);
+        mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, TEST_PROBE_FRAME, TEST_MCS_RATE,
+                Runnable::run, cb2);
         verify(cb2).onFailure(WifiCondManager.SEND_MGMT_FRAME_ERROR_ALREADY_STARTED);
         // verify SendMgmtFrame() still was only called once i.e. not called again
         verify(mClientInterface, times(1))
@@ -820,8 +833,8 @@
         doNothing().when(mAlarmManager).set(anyInt(), anyLong(), any(),
                 alarmListenerCaptor.capture(), handlerCaptor.capture());
 
-        mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, TEST_PROBE_FRAME,
-                cb, TEST_MCS_RATE);
+        mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, TEST_PROBE_FRAME, TEST_MCS_RATE,
+                Runnable::run, cb);
         mLooper.dispatchAll();
 
         verify(cb).onFailure(anyInt());
@@ -854,7 +867,8 @@
         final ArgumentCaptor<Handler> handlerCaptor = ArgumentCaptor.forClass(Handler.class);
         doNothing().when(mAlarmManager).set(anyInt(), anyLong(), any(),
                 alarmListenerCaptor.capture(), handlerCaptor.capture());
-        mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, TEST_PROBE_FRAME, cb, TEST_MCS_RATE);
+        mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, TEST_PROBE_FRAME, TEST_MCS_RATE,
+                Runnable::run, cb);
 
         sendMgmtFrameEventCaptor.getValue().OnAck(TEST_SEND_MGMT_FRAME_ELAPSED_TIME_MS);
         mLooper.dispatchAll();
@@ -887,7 +901,8 @@
         final ArgumentCaptor<Handler> handlerCaptor = ArgumentCaptor.forClass(Handler.class);
         doNothing().when(mAlarmManager).set(anyInt(), anyLong(), any(),
                 alarmListenerCaptor.capture(), handlerCaptor.capture());
-        mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, TEST_PROBE_FRAME, cb, TEST_MCS_RATE);
+        mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, TEST_PROBE_FRAME, TEST_MCS_RATE,
+                Runnable::run, cb);
 
         sendMgmtFrameEventCaptor.getValue().OnFailure(
                 WifiCondManager.SEND_MGMT_FRAME_ERROR_UNKNOWN);
@@ -921,7 +936,8 @@
         final ArgumentCaptor<Handler> handlerCaptor = ArgumentCaptor.forClass(Handler.class);
         doNothing().when(mAlarmManager).set(anyInt(), anyLong(), any(),
                 alarmListenerCaptor.capture(), handlerCaptor.capture());
-        mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, TEST_PROBE_FRAME, cb, TEST_MCS_RATE);
+        mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, TEST_PROBE_FRAME, TEST_MCS_RATE,
+                Runnable::run, cb);
 
         handlerCaptor.getValue().post(() -> alarmListenerCaptor.getValue().onAlarm());
         mLooper.dispatchAll();
@@ -987,8 +1003,8 @@
         final ArgumentCaptor<Handler> handlerCaptor = ArgumentCaptor.forClass(Handler.class);
         doNothing().when(mAlarmManager).set(anyInt(), anyLong(), any(),
                 alarmListenerCaptor.capture(), handlerCaptor.capture());
-        mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, TEST_PROBE_FRAME,
-                mSendMgmtFrameCallback, TEST_MCS_RATE);
+        mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, TEST_PROBE_FRAME, TEST_MCS_RATE,
+                Runnable::run, mSendMgmtFrameCallback);
 
         // AlarmManager should post the onAlarm() callback onto the handler, but since we are
         // triggering onAlarm() ourselves during the test, manually post onto handler
@@ -1015,8 +1031,8 @@
         final ArgumentCaptor<Handler> handlerCaptor = ArgumentCaptor.forClass(Handler.class);
         doNothing().when(mAlarmManager).set(anyInt(), anyLong(), any(),
                 alarmListenerCaptor.capture(), handlerCaptor.capture());
-        mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, TEST_PROBE_FRAME,
-                mSendMgmtFrameCallback, TEST_MCS_RATE);
+        mWificondControl.sendMgmtFrame(TEST_INTERFACE_NAME, TEST_PROBE_FRAME, TEST_MCS_RATE,
+                Runnable::run, mSendMgmtFrameCallback);
 
         // AlarmManager should post the onAlarm() callback onto the handler, but since we are
         // triggering onAlarm() ourselves during the test, manually post onto handler
@@ -1086,56 +1102,6 @@
         }
     }
 
-    // Create a ArgumentMatcher which captures a PnoSettings parameter and checks if it
-    // matches the WifiNative.PnoSettings;
-    private class PnoScanMatcher implements ArgumentMatcher<PnoSettings> {
-        private final PnoSettings mExpectedPnoSettings;
-
-        PnoScanMatcher(PnoSettings expectedPnoSettings) {
-            this.mExpectedPnoSettings = expectedPnoSettings;
-        }
-
-        @Override
-        public boolean matches(PnoSettings settings) {
-            if (mExpectedPnoSettings == null) {
-                return false;
-            }
-            if (settings.intervalMs != mExpectedPnoSettings.intervalMs
-                    || settings.min2gRssi != mExpectedPnoSettings.min2gRssi
-                    || settings.min5gRssi != mExpectedPnoSettings.min5gRssi
-                    || settings.min6gRssi != mExpectedPnoSettings.min6gRssi) {
-                return false;
-            }
-            if (settings.pnoNetworks == null || mExpectedPnoSettings.pnoNetworks == null) {
-                return false;
-            }
-            if (settings.pnoNetworks.size() != mExpectedPnoSettings.pnoNetworks.size()) {
-                return false;
-            }
-
-            for (int i = 0; i < settings.pnoNetworks.size(); i++) {
-                if (!Arrays.equals(settings.pnoNetworks.get(i).ssid,
-                        mExpectedPnoSettings.pnoNetworks.get(i).ssid)) {
-                    return false;
-                }
-                if (settings.pnoNetworks.get(i).isHidden != mExpectedPnoSettings.pnoNetworks.get(
-                        i).isHidden) {
-                    return false;
-                }
-                if (!Arrays.equals(settings.pnoNetworks.get(i).frequencies,
-                        mExpectedPnoSettings.pnoNetworks.get(i).frequencies)) {
-                    return false;
-                }
-            }
-            return true;
-        }
-
-        @Override
-        public String toString() {
-            return "PnoScanMatcher{" + "mExpectedPnoSettings=" + mExpectedPnoSettings + '}';
-        }
-    }
-
     private static class LocalNativeUtil {
         private static final int SSID_BYTES_MAX_LEN = 32;